├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── feature.yml │ └── help.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── labels.yml ├── release.yml └── workflows │ ├── ci.yml │ ├── codeql.yml │ ├── integration_tests_pr.yml │ ├── labeler.yml │ ├── nightly_smoke_tests.yml │ ├── release-cross-repo-test.yml │ ├── release-notify-slack.yml │ ├── security_pr.yml │ └── stale.yml ├── .gitignore ├── .gitmodules ├── .golangci.yml ├── CODEOWNERS ├── LICENSE ├── Makefile ├── README.md ├── account.go ├── account_agreements.go ├── account_availability.go ├── account_betas.go ├── account_child.go ├── account_events.go ├── account_invoices.go ├── account_logins.go ├── account_maintenance.go ├── account_notifications.go ├── account_oauth_client.go ├── account_payment_methods.go ├── account_payments.go ├── account_promo_credits.go ├── account_service_transfer.go ├── account_settings.go ├── account_transfer.go ├── account_user_grants.go ├── account_users.go ├── base_types.go ├── betas.go ├── client.go ├── client_http.go ├── client_test.go ├── config.go ├── config_test.go ├── databases.go ├── domain_records.go ├── domains.go ├── env.sample ├── errors.go ├── errors_test.go ├── filter.go ├── filter_test.go ├── firewall_devices.go ├── firewall_rules.go ├── firewalls.go ├── go.mod ├── go.sum ├── go.work ├── go.work.sum ├── images.go ├── instance_config_interfaces.go ├── instance_configs.go ├── instance_disks.go ├── instance_firewalls.go ├── instance_ips.go ├── instance_nodebalancers.go ├── instance_snapshots.go ├── instance_stats.go ├── instance_volumes.go ├── instances.go ├── internal ├── duration │ ├── duration.go │ └── duration_test.go ├── parseabletime │ └── parseable_time.go └── testutil │ └── mock.go ├── k8s ├── clientset.go ├── go.mod ├── go.sum └── pkg │ └── condition │ └── lke.go ├── kernels.go ├── lke_cluster_pools.go ├── lke_clusters.go ├── lke_clusters_control_plane.go ├── lke_node_pools.go ├── lke_types.go ├── logger.go ├── longview.go ├── longview_subscriptions.go ├── monitor_dashboards.go ├── monitor_metrics_definitions.go ├── monitor_services.go ├── monitor_services_create_token.go ├── mysql.go ├── network_ips.go ├── network_pools.go ├── network_ranges.go ├── network_reserved_ips.go ├── network_transfer_prices.go ├── nodebalancer.go ├── nodebalancer_config_nodes.go ├── nodebalancer_config_vpc.go ├── nodebalancer_configs.go ├── nodebalancer_firewalls.go ├── nodebalancer_stats.go ├── nodebalancer_types.go ├── object_storage.go ├── object_storage_bucket_certs.go ├── object_storage_buckets.go ├── object_storage_clusters.go ├── object_storage_endpoints.go ├── object_storage_keys.go ├── object_storage_object.go ├── object_storage_quota.go ├── paged_response_structs.go ├── pagination.go ├── pagination_test.go ├── placement_groups.go ├── pointer_helpers.go ├── pointer_helpers_test.go ├── postgres.go ├── profile.go ├── profile_apps.go ├── profile_devices.go ├── profile_grants_list.go ├── profile_logins.go ├── profile_phone_number.go ├── profile_preferences.go ├── profile_security_questions.go ├── profile_sshkeys.go ├── profile_tfa.go ├── profile_tokens.go ├── regions.go ├── regions_availability.go ├── request_helpers.go ├── request_helpers_test.go ├── retries.go ├── retries_http.go ├── retries_http_test.go ├── retries_test.go ├── scripts ├── lke-policy.yaml ├── lke_calico_rules_e2e.sh ├── update_fixtures_contains_specific_string.py └── verify-gomod-tidy.sh ├── stackscripts.go ├── support.go ├── tags.go ├── test ├── Makefile ├── go.mod ├── go.sum ├── integration │ ├── TestReservedIPAddresses_GetInstanceIPReservationStatus.yaml │ ├── account_agreements_test.go │ ├── account_availability_test.go │ ├── account_betas_test.go │ ├── account_child_test.go │ ├── account_events_test.go │ ├── account_logins_test.go │ ├── account_maintenance_test.go │ ├── account_notifications_test.go │ ├── account_oauth_client_test.go │ ├── account_payments_test.go │ ├── account_settings_test.go │ ├── account_test.go │ ├── account_transfer_test.go │ ├── account_user_grants_test.go │ ├── account_users_test.go │ ├── betas_test.go │ ├── cache_test.go │ ├── databases_test.go │ ├── domain_records_test.go │ ├── domains_test.go │ ├── example_integration_test.go │ ├── example_nodebalancers_test.go │ ├── example_stackscripts_test.go │ ├── example_test.go │ ├── firewall_rules_test.go │ ├── firewalls_devices_test.go │ ├── firewalls_test.go │ ├── fixtures │ │ ├── ExampleCreateNodeBalancer.yaml │ │ ├── ExampleCreateNodeBalancerConfig.yaml │ │ ├── ExampleCreateNodeBalancerNode.yaml │ │ ├── ExampleCreateStackscript.yaml │ │ ├── ExampleGetAccount.yaml │ │ ├── ExampleGetImage_missing.yaml │ │ ├── ExampleGetKernel_specific.yaml │ │ ├── ExampleGetType_missing.yaml │ │ ├── ExampleListImages_all.yaml │ │ ├── ExampleListImages_badfilter.yaml │ │ ├── ExampleListImages_notfound.yaml │ │ ├── ExampleListKernels_all.yaml │ │ ├── ExampleListKernels_allWithOpts.yaml │ │ ├── ExampleListKernels_filtered.yaml │ │ ├── ExampleListKernels_page1.yaml │ │ ├── ExampleListLongviewSubscriptions_page1.yaml │ │ ├── ExampleListStackscripts_page1.yaml │ │ ├── ExampleListTypes_all.yaml │ │ ├── ExampleListUsers.yaml │ │ ├── TestAccountAgreements_List.yaml │ │ ├── TestAccountAvailability_Get.yaml │ │ ├── TestAccountAvailability_List.yaml │ │ ├── TestAccountBetaPrograms.yaml │ │ ├── TestAccountChild_basic.yaml │ │ ├── TestAccountEvents_List.yaml │ │ ├── TestAccountLogins_List.yaml │ │ ├── TestAccountMaintenances_List.yaml │ │ ├── TestAccountNotifications_List.yaml │ │ ├── TestAccountSettings.yaml │ │ ├── TestAccountTransfer_Get.yaml │ │ ├── TestAccount_Get.yaml │ │ ├── TestBetaProgram_Get.yaml │ │ ├── TestBetaPrograms_List.yaml │ │ ├── TestCache_Expiration.yaml │ │ ├── TestCache_RegionList.yaml │ │ ├── TestClient_APIResponseBadGateway.yaml │ │ ├── TestDatabaseACLP_List.yaml │ │ ├── TestDatabaseMySQL_EngineConfig_Create_NullableFieldAsNilValue.yaml │ │ ├── TestDatabaseMySQL_EngineConfig_Get.yaml │ │ ├── TestDatabaseMySQL_EngineConfig_Suite.yaml │ │ ├── TestDatabasePostgres_EngineConfig_Create_PasswordEncryption_DefaultsToMD5.yaml │ │ ├── TestDatabasePostgres_EngineConfig_Get.yaml │ │ ├── TestDatabasePostgres_EngineConfig_Suite.yaml │ │ ├── TestDatabase_Engine.yaml │ │ ├── TestDatabase_List.yaml │ │ ├── TestDatabase_MySQL_Suite.yaml │ │ ├── TestDatabase_Postgres_Suite.yaml │ │ ├── TestDatabase_Type.yaml │ │ ├── TestDomainRecord_Create.yaml │ │ ├── TestDomainRecord_Get.yaml │ │ ├── TestDomainRecord_Update.yaml │ │ ├── TestDomainRecords_List.yaml │ │ ├── TestDomainRecords_ListMultiplePages.yaml │ │ ├── TestDomain_Clone.yaml │ │ ├── TestDomain_Create.yaml │ │ ├── TestDomain_Get.yaml │ │ ├── TestDomain_Update.yaml │ │ ├── TestDomain_ZoneFile_Get.yaml │ │ ├── TestDomains_List.yaml │ │ ├── TestEventPoller_InstancePower.yaml │ │ ├── TestEventPoller_Secondary.yaml │ │ ├── TestFirewallDevice_Delete.yaml │ │ ├── TestFirewallDevice_Get.yaml │ │ ├── TestFirewallDevices_List.yaml │ │ ├── TestFirewallRules_Get.yaml │ │ ├── TestFirewallRules_Update.yaml │ │ ├── TestFirewall_Get.yaml │ │ ├── TestFirewall_Update.yaml │ │ ├── TestFirewalls_List.yaml │ │ ├── TestGetPayment_found.yaml │ │ ├── TestGrantsList.yaml │ │ ├── TestIPAddress_GetFound.yaml │ │ ├── TestIPAddress_GetMissing.yaml │ │ ├── TestIPAddress_Instance_Allocate.yaml │ │ ├── TestIPAddress_Instance_Assign.yaml │ │ ├── TestIPAddress_Instance_Delete.yaml │ │ ├── TestIPAddress_Instance_ReserveIP_Assign.yaml │ │ ├── TestIPAddress_Instance_Share.yaml │ │ ├── TestIPAddress_Update.yaml │ │ ├── TestIPAddresses_Instance_Get.yaml │ │ ├── TestIPAddresses_List.yaml │ │ ├── TestIPv6Pool_Get.yaml │ │ ├── TestIPv6Pool_List.yaml │ │ ├── TestIPv6Range_Instance_List.yaml │ │ ├── TestIPv6Range_Share.yaml │ │ ├── TestImage_CloudInit.yaml │ │ ├── TestImage_CreateUpload.yaml │ │ ├── TestImage_GetFound.yaml │ │ ├── TestImage_GetMissing.yaml │ │ ├── TestImage_Replicate.yaml │ │ ├── TestImage_Upload.yaml │ │ ├── TestImages_List.yaml │ │ ├── TestInstanceBackups_List.yaml │ │ ├── TestInstanceFirewalls_List.yaml │ │ ├── TestInstance_AddReservedIPToInstance.yaml │ │ ├── TestInstance_AddReservedIPToInstanceVariants.yaml │ │ ├── TestInstance_Clone.yaml │ │ ├── TestInstance_ConfigInterface_Update.yaml │ │ ├── TestInstance_ConfigInterfaces_AppendDelete.yaml │ │ ├── TestInstance_ConfigInterfaces_List.yaml │ │ ├── TestInstance_ConfigInterfaces_Reorder.yaml │ │ ├── TestInstance_ConfigInterfaces_Update.yaml │ │ ├── TestInstance_Config_Update.yaml │ │ ├── TestInstance_Configs_List.yaml │ │ ├── TestInstance_CreateUnderFirewall.yaml │ │ ├── TestInstance_CreateWithAlreadyAssignedReservedIP.yaml │ │ ├── TestInstance_CreateWithEmptyIPAddress.yaml │ │ ├── TestInstance_CreateWithMultipleIPAddresses.yaml │ │ ├── TestInstance_CreateWithNonOwnedReservedAddress.yaml │ │ ├── TestInstance_CreateWithNonReservedAddress.yaml │ │ ├── TestInstance_CreateWithNullIPAddress.yaml │ │ ├── TestInstance_CreateWithOwnedNonAssignedReservedIP.yaml │ │ ├── TestInstance_CreateWithReservedIPAddress.yaml │ │ ├── TestInstance_CreateWithReservedIPAddressVariants.yaml │ │ ├── TestInstance_CreateWithoutIPv4Field.yaml │ │ ├── TestInstance_DeleteInstanceVariants.yaml │ │ ├── TestInstance_DiskEncryption.yaml │ │ ├── TestInstance_Disk_Clone.yaml │ │ ├── TestInstance_Disk_ListMultiple_Primary.yaml │ │ ├── TestInstance_Disk_ListMultiple_Secondary.yaml │ │ ├── TestInstance_Disk_ResetPassword.yaml │ │ ├── TestInstance_Disk_Resize.yaml │ │ ├── TestInstance_Disks_List.yaml │ │ ├── TestInstance_Disks_List_WithEncryption.yaml │ │ ├── TestInstance_Get.yaml │ │ ├── TestInstance_GetMonthlyTransfer.yaml │ │ ├── TestInstance_GetTransfer.yaml │ │ ├── TestInstance_Migrate.yaml │ │ ├── TestInstance_MigrateToPG.yaml │ │ ├── TestInstance_NodeBalancers_List.yaml │ │ ├── TestInstance_Rebuild.yaml │ │ ├── TestInstance_RebuildWithEncryption.yaml │ │ ├── TestInstance_ResetPassword.yaml │ │ ├── TestInstance_Resize.yaml │ │ ├── TestInstance_Volumes_List.yaml │ │ ├── TestInstance_Volumes_List_Instance.yaml │ │ ├── TestInstance_withBlockStorageEncryption.yaml │ │ ├── TestInstance_withMetadata.yaml │ │ ├── TestInstance_withPG.yaml │ │ ├── TestInstance_withVPU.yaml │ │ ├── TestInstances_List.yaml │ │ ├── TestLKECluster_APIEndpoints_List.yaml │ │ ├── TestLKECluster_APLEnabled.yaml │ │ ├── TestLKECluster_Dashboard_Get.yaml │ │ ├── TestLKECluster_Enterprise_smoke.yaml │ │ ├── TestLKECluster_GetFound.yaml │ │ ├── TestLKECluster_GetMissing.yaml │ │ ├── TestLKECluster_Kubeconfig_Delete.yaml │ │ ├── TestLKECluster_Kubeconfig_Get.yaml │ │ ├── TestLKECluster_Nodes_Recycle.yaml │ │ ├── TestLKECluster_Update.yaml │ │ ├── TestLKECluster_WaitForReady.yaml │ │ ├── TestLKECluster_WaitForReady_Cluster.yaml │ │ ├── TestLKECluster_withACL.yaml │ │ ├── TestLKEClusters_List.yaml │ │ ├── TestLKENodeEnterprisePoolNode_Get.yaml │ │ ├── TestLKENodeEnterprisePoolNode_Update.yaml │ │ ├── TestLKENodePoolNode_Delete.yaml │ │ ├── TestLKENodePoolNode_Get.yaml │ │ ├── TestLKENodePoolNode_Recycle.yaml │ │ ├── TestLKENodePool_CreateWithLabelsAndTaints.yaml │ │ ├── TestLKENodePool_GetFound.yaml │ │ ├── TestLKENodePool_GetFound_k8s.yaml │ │ ├── TestLKENodePool_GetMissing.yaml │ │ ├── TestLKENodePool_Recycle.yaml │ │ ├── TestLKENodePool_Update.yaml │ │ ├── TestLKENodePools_List.yaml │ │ ├── TestLKETierVersion_ListAndGet.yaml │ │ ├── TestLKEType_List.yaml │ │ ├── TestLKEVersion_GetFound.yaml │ │ ├── TestLKEVersion_GetMissing.yaml │ │ ├── TestLKEVersions_List.yaml │ │ ├── TestLongviewClient_Create.yaml │ │ ├── TestLongviewClient_Delete.yaml │ │ ├── TestLongviewClient_Get.yaml │ │ ├── TestLongviewClient_List.yaml │ │ ├── TestLongviewClient_Update.yaml │ │ ├── TestLongviewPlan_Get.yaml │ │ ├── TestLongviewPlan_Update.yaml │ │ ├── TestMonitorDashboards_Get.yaml │ │ ├── TestMonitorMetricDefinitions_Get.yaml │ │ ├── TestMonitorServices_Get.yaml │ │ ├── TestNetworkTransferPrice_List.yaml │ │ ├── TestNodeBalancerConfig_Create.yaml │ │ ├── TestNodeBalancerConfig_Get.yaml │ │ ├── TestNodeBalancerConfig_Rebuild_InVPCWithInstance.yaml │ │ ├── TestNodeBalancerConfig_UDP.yaml │ │ ├── TestNodeBalancerConfig_Update.yaml │ │ ├── TestNodeBalancerConfigs_List.yaml │ │ ├── TestNodeBalancerConfigs_ListMultiplePages.yaml │ │ ├── TestNodeBalancerFirewalls_List.yaml │ │ ├── TestNodeBalancerNode_Create.yaml │ │ ├── TestNodeBalancerNode_CreateInstance.yaml │ │ ├── TestNodeBalancerNode_Create_InVPC.yaml │ │ ├── TestNodeBalancerNode_Get.yaml │ │ ├── TestNodeBalancerNode_GetInstance.yaml │ │ ├── TestNodeBalancerNode_Get_InVPC.yaml │ │ ├── TestNodeBalancerNode_List_InVPC.yaml │ │ ├── TestNodeBalancerNode_Update.yaml │ │ ├── TestNodeBalancerNode_UpdateInstance.yaml │ │ ├── TestNodeBalancerNode_Update_InVPC.yaml │ │ ├── TestNodeBalancerNodes_List.yaml │ │ ├── TestNodeBalancerNodes_ListInstance.yaml │ │ ├── TestNodeBalancerNodes_ListMultiplePages.yaml │ │ ├── TestNodeBalancerNodes_ListMultiplePagesInstance.yaml │ │ ├── TestNodeBalancerStats_Get.yaml │ │ ├── TestNodeBalancerType_List.yaml │ │ ├── TestNodeBalancerVpcConfig_Get.yaml │ │ ├── TestNodeBalancerVpcConfig_List.yaml │ │ ├── TestNodeBalancer_Create.yaml │ │ ├── TestNodeBalancer_Create_Type.yaml │ │ ├── TestNodeBalancer_Get.yaml │ │ ├── TestNodeBalancer_Rebuild.yaml │ │ ├── TestNodeBalancer_RebuildInstance.yaml │ │ ├── TestNodeBalancer_UDP.yaml │ │ ├── TestNodeBalancer_Update.yaml │ │ ├── TestNodeBalancer_With_VPC_Create.yaml │ │ ├── TestNodeBalancers_List.yaml │ │ ├── TestOAuthClient_GetFound.yaml │ │ ├── TestOAuthClient_GetMissing.yaml │ │ ├── TestOAuthClients_List.yaml │ │ ├── TestOAuthClients_Reset.yaml │ │ ├── TestObjectStorageBucketCert.yaml │ │ ├── TestObjectStorageBucket_Access_Get.yaml │ │ ├── TestObjectStorageBucket_Access_Update.yaml │ │ ├── TestObjectStorageBucket_Create.yaml │ │ ├── TestObjectStorageBucket_GetFound.yaml │ │ ├── TestObjectStorageBucket_GetMissing.yaml │ │ ├── TestObjectStorageBucket_Regional.yaml │ │ ├── TestObjectStorageBucketsInCluster_List.yaml │ │ ├── TestObjectStorageBuckets_List.yaml │ │ ├── TestObjectStorageClusters_List.yaml │ │ ├── TestObjectStorageKey_GetFound.yaml │ │ ├── TestObjectStorageKey_GetMissing.yaml │ │ ├── TestObjectStorageKey_List.yaml │ │ ├── TestObjectStorageKey_Update.yaml │ │ ├── TestObjectStorageKeys_Limited.yaml │ │ ├── TestObjectStorageKeys_Limited_Bucket.yaml │ │ ├── TestObjectStorageKeys_Regional_Limited.yaml │ │ ├── TestObjectStorageObject_ACLConfig_Bucket_Delete.yaml │ │ ├── TestObjectStorageObject_ACLConfig_Bucket_Put.yaml │ │ ├── TestObjectStorageObject_ACLConfig_Update.yaml │ │ ├── TestObjectStorageObject_Smoke.yaml │ │ ├── TestObjectStorageQuotaUsage_Get.yaml │ │ ├── TestObjectStorageQuotas_Get.yaml │ │ ├── TestObjectStorageQuotas_List.yaml │ │ ├── TestObjectStorage_transfer.yaml │ │ ├── TestPayment_GetFound.yaml │ │ ├── TestPayment_GetMissing.yaml │ │ ├── TestPayments_List.yaml │ │ ├── TestPlacementGroup_assignment.yaml │ │ ├── TestPlacementGroup_basic.yaml │ │ ├── TestProfileLogins_List.yaml │ │ ├── TestProfile_Get.yaml │ │ ├── TestProfile_Update.yaml │ │ ├── TestRegionsAvailability_List.yaml │ │ ├── TestRegions_List.yaml │ │ ├── TestRegions_blockStorageEncryption.yaml │ │ ├── TestRegions_kubernetesEnterprise.yaml │ │ ├── TestRegions_pgLimits.yaml │ │ ├── TestReservedIPAddresses_DeleteIPAddressVariants.yaml │ │ ├── TestReservedIPAddresses_EndToEndTest.yaml │ │ ├── TestReservedIPAddresses_ExceedLimit.yaml │ │ ├── TestReservedIPAddresses_GetIPAddressVariants.yaml │ │ ├── TestReservedIPAddresses_InsufficientPermissions.yaml │ │ ├── TestReservedIPAddresses_ListIPAddressesVariants.yaml │ │ ├── TestReservedIPAddresses_ReserveIPVariants.yaml │ │ ├── TestSSHKey_GetFound.yaml │ │ ├── TestSSHKey_GetMissing.yaml │ │ ├── TestSSHKey_Update.yaml │ │ ├── TestSSHKeys_List.yaml │ │ ├── TestSecurityQuestions_List.yaml │ │ ├── TestServiceToken_POST.yaml │ │ ├── TestStackscripts_List.yaml │ │ ├── TestTag_Create.yaml │ │ ├── TestTag_ListTaggedObjects_Missing.yaml │ │ ├── TestToken_GetFound.yaml │ │ ├── TestToken_GetMissing.yaml │ │ ├── TestToken_GetNoExpiry.yaml │ │ ├── TestTokens_List.yaml │ │ ├── TestTokens_Update.yaml │ │ ├── TestType_GetFound.yaml │ │ ├── TestType_GetMissing.yaml │ │ ├── TestTypes_List.yaml │ │ ├── TestTypes_RegionSpecific.yaml │ │ ├── TestUserGrants_Update.yaml │ │ ├── TestUserGrants_UpdateNoAccess.yaml │ │ ├── TestUser_Get.yaml │ │ ├── TestUser_GetMissing.yaml │ │ ├── TestUser_Update.yaml │ │ ├── TestUsers_List.yaml │ │ ├── TestVLANs_GetIPAMAddress.yaml │ │ ├── TestVLANs_List.yaml │ │ ├── TestVPC_CreateGet.yaml │ │ ├── TestVPC_Create_Invalid.yaml │ │ ├── TestVPC_List.yaml │ │ ├── TestVPC_ListAllIPAddresses.yaml │ │ ├── TestVPC_ListIPAddresses.yaml │ │ ├── TestVPC_Subnet_Create.yaml │ │ ├── TestVPC_Subnet_Create_Invalid_data.yaml │ │ ├── TestVPC_Subnet_List.yaml │ │ ├── TestVPC_Subnet_Update.yaml │ │ ├── TestVPC_Subnet_Update_Invalid_Label.yaml │ │ ├── TestVPC_Subnet_WithInstance.yaml │ │ ├── TestVPC_Update.yaml │ │ ├── TestVPC_Update_Invalid.yaml │ │ ├── TestVolumeType_List.yaml │ │ ├── TestVolume_Create.yaml │ │ ├── TestVolume_Create_withEncryption.yaml │ │ ├── TestVolume_Get.yaml │ │ ├── TestVolume_Get_withEncryption.yaml │ │ ├── TestVolume_List.yaml │ │ ├── TestVolume_Resize.yaml │ │ ├── TestVolume_Update.yaml │ │ ├── TestVolume_WaitForLinodeID_linode.yaml │ │ ├── TestVolume_WaitForLinodeID_nil.yaml │ │ ├── TestVolume_WaitForLinodeID_volume.yaml │ │ ├── TestVolume_WaitForLinodeID_waiting.yaml │ │ ├── TestVolumes_List.yaml │ │ └── TestWaitForResourceFree.yaml │ ├── images_test.go │ ├── instance_config_test.go │ ├── instance_firewalls_test.go │ ├── instance_reserved_ips_test.go │ ├── instance_snapshots_test.go │ ├── instances_test.go │ ├── integration_suite_test.go │ ├── lke_clusters_acl_test.go │ ├── lke_clusters_test.go │ ├── lke_node_pools_test.go │ ├── lke_types_test.go │ ├── longview_test.go │ ├── main_test.go │ ├── monitor_dashboards_test.go │ ├── monitor_metrics_definitions_test.go │ ├── monitor_services_test.go │ ├── monitor_services_token_creation_test.go │ ├── mysql_db_config_test.go │ ├── mysql_test.go │ ├── network_ips_test.go │ ├── network_pools_test.go │ ├── network_ranges_test.go │ ├── network_reserved_ips_test.go │ ├── network_transfer_prices_test.go │ ├── nodebalancer_config_nodes_test.go │ ├── nodebalancer_config_vpc_test.go │ ├── nodebalancer_configs_test.go │ ├── nodebalancer_firewalls_test.go │ ├── nodebalancer_stats_test.go │ ├── nodebalancer_types_test.go │ ├── nodebalancers_test.go │ ├── object_storage_bucket_certs_test.go │ ├── object_storage_buckets_test.go │ ├── object_storage_clusters_test.go │ ├── object_storage_keys_test.go │ ├── object_storage_object_test.go │ ├── object_storage_quota_test.go │ ├── placement_group_test.go │ ├── postgres_db_config_test.go │ ├── postgres_test.go │ ├── profile_logins_test.go │ ├── profile_security_question_test.go │ ├── profile_sshkeys_test.go │ ├── profile_test.go │ ├── profile_tokens_test.go │ ├── regions_test.go │ ├── regionsavailability_test.go │ ├── stackscripts_test.go │ ├── tags_test.go │ ├── test_retry.go │ ├── types_test.go │ ├── util_test.go │ ├── vlans_test.go │ ├── volume_types_test.go │ ├── volumes_test.go │ ├── vpc_subnet_test.go │ ├── vpc_test.go │ └── waitfor_test.go └── unit │ ├── .DS_Store │ ├── account_agreements_test.go │ ├── account_availability_test.go │ ├── account_betas_test.go │ ├── account_child_test.go │ ├── account_events_test.go │ ├── account_invoices_test.go │ ├── account_logins_test.go │ ├── account_maintenance_test.go │ ├── account_notifications_test.go │ ├── account_oauth_client_test.go │ ├── account_payment_methods_test.go │ ├── account_payments_test.go │ ├── account_promo_credits_test.go │ ├── account_service_transfer_test.go │ ├── account_settings_test.go │ ├── account_test.go │ ├── account_transfer_test.go │ ├── account_user_grants_test.go │ ├── account_users_test.go │ ├── base.go │ ├── client_test.go │ ├── database_test.go │ ├── domain_test.go │ ├── domainrecord_test.go │ ├── firewall_devices_test.go │ ├── firewall_rules_test.go │ ├── firewalls_test.go │ ├── fixtures.go │ ├── fixtures │ ├── account_agreements_get.json │ ├── account_availability_get.json │ ├── account_availability_list.json │ ├── account_beta_get.json │ ├── account_beta_list.json │ ├── account_child_create_token.json │ ├── account_child_get.json │ ├── account_child_list.json │ ├── account_events_get.json │ ├── account_events_list.json │ ├── account_get.json │ ├── account_invoice_items_list.json │ ├── account_invoices_get.json │ ├── account_invoices_list.json │ ├── account_logins_get.json │ ├── account_logins_list.json │ ├── account_maintenance_list.json │ ├── account_notifications_list.json │ ├── account_oauth_client_create.json │ ├── account_oauth_client_get.json │ ├── account_oauth_client_list.json │ ├── account_oauth_client_reset.json │ ├── account_oauth_client_update.json │ ├── account_payment_create.json │ ├── account_payment_methods_get.json │ ├── account_payment_methods_list.json │ ├── account_promo_credits_add_promo_code.json │ ├── account_service_transfers_get.json │ ├── account_service_transfers_list.json │ ├── account_service_transfers_request.json │ ├── account_settings_get.json │ ├── account_settings_update.json │ ├── account_transfer_get.json │ ├── account_update.json │ ├── account_user_grants_get.json │ ├── account_user_grants_update.json │ ├── account_users_create.json │ ├── account_users_get.json │ ├── account_users_list.json │ ├── account_users_update.json │ ├── database_engine_get.json │ ├── database_maintenance_window.json │ ├── database_types_list.json │ ├── database_unmarshal.json │ ├── databases_list.json │ ├── domain_clone.json │ ├── domain_create.json │ ├── domain_get.json │ ├── domain_get_domainzonefile.json │ ├── domain_import.json │ ├── domain_list.json │ ├── domain_update.json │ ├── domainrecord_create.json │ ├── domainrecord_get.json │ ├── domainrecord_list.json │ ├── domainrecord_update.json │ ├── firewall_create.json │ ├── firewall_device_create.json │ ├── firewall_device_get.json │ ├── firewall_device_list.json │ ├── firewall_get.json │ ├── firewall_list.json │ ├── firewall_rule_get.json │ ├── firewall_rule_update.json │ ├── firewall_update.json │ ├── image_create.json │ ├── image_get.json │ ├── image_replicate.json │ ├── image_update.json │ ├── image_upload.json │ ├── images_list.json │ ├── instance_backups_get.json │ ├── instance_clone.json │ ├── instance_config_create.json │ ├── instance_config_get.json │ ├── instance_config_interface_create.json │ ├── instance_config_interface_get.json │ ├── instance_config_interface_list.json │ ├── instance_config_interface_update.json │ ├── instance_config_list.json │ ├── instance_config_update.json │ ├── instance_create.json │ ├── instance_disk_create.json │ ├── instance_disk_get.json │ ├── instance_disk_list.json │ ├── instance_disk_update.json │ ├── instance_disks_clone.json │ ├── instance_firewall_list.json │ ├── instance_get.json │ ├── instance_ip_add.json │ ├── instance_ip_get.json │ ├── instance_ip_list.json │ ├── instance_ip_reserved.json │ ├── instance_ip_update.json │ ├── instance_monthly_transfer_get.json │ ├── instance_nodebalancers_list.json │ ├── instance_rebuild.json │ ├── instance_snapshot_create.json │ ├── instance_snapshot_get.json │ ├── instance_stats_get.json │ ├── instance_update.json │ ├── instance_volume_list.json │ ├── linode_type_get.json │ ├── linode_types_list.json │ ├── linodes_list.json │ ├── lke_cluster_apl.json │ ├── lke_cluster_control_plane_acl_get.json │ ├── lke_cluster_control_plane_acl_update.json │ ├── lke_cluster_create.json │ ├── lke_cluster_dashboard.json │ ├── lke_cluster_get.json │ ├── lke_cluster_kubeconfig.json │ ├── lke_cluster_list.json │ ├── lke_cluster_pool_create.json │ ├── lke_cluster_pool_get.json │ ├── lke_cluster_pool_list.json │ ├── lke_cluster_pool_update.json │ ├── lke_cluster_regenerate.json │ ├── lke_cluster_update.json │ ├── lke_e_node_pool_create.json │ ├── lke_e_node_pool_update.json │ ├── lke_node_pool_create.json │ ├── lke_node_pool_get.json │ ├── lke_node_pool_list.json │ ├── lke_node_pool_node_get.json │ ├── lke_node_pool_update.json │ ├── lke_types_list.json │ ├── longview_client_single.json │ ├── longview_clients_list.json │ ├── longview_plan.json │ ├── longview_subscription_get.json │ ├── longview_subscriptions_list.json │ ├── monitor_dashboard_by_id.json │ ├── monitor_dashboard_by_service_type.json │ ├── monitor_dashboards.json │ ├── monitor_service_metrics.json │ ├── monitor_service_token_create.json │ ├── monitor_services.json │ ├── mysql_database_config_get.json │ ├── mysql_database_create.json │ ├── mysql_database_credentials_get.json │ ├── mysql_database_get.json │ ├── mysql_database_ssl_get.json │ ├── mysql_database_update.json │ ├── mysql_databases_list.json │ ├── network_ip_address_get.json │ ├── network_ip_addresses_list.json │ ├── network_ipv6_pools_get.json │ ├── network_ipv6_pools_list.json │ ├── network_ipv6_ranges_create.json │ ├── network_ipv6_ranges_get.json │ ├── network_ipv6_ranges_list.json │ ├── network_reserved_ips.json │ ├── network_reserved_ips_get.json │ ├── network_reserved_ips_list.json │ ├── nodebalancer_config_create.json │ ├── nodebalancer_config_get.json │ ├── nodebalancer_config_list.json │ ├── nodebalancer_config_rebuild.json │ ├── nodebalancer_config_update.json │ ├── nodebalancer_create.json │ ├── nodebalancer_firewall_list.json │ ├── nodebalancer_get.json │ ├── nodebalancer_node_create.json │ ├── nodebalancer_node_list.json │ ├── nodebalancer_node_update.json │ ├── nodebalancer_stats_get.json │ ├── nodebalancer_update.json │ ├── nodebalancers_configs_create_udp.json │ ├── nodebalancers_create_udp.json │ ├── nodebalancers_list.json │ ├── nodebalancers_types_list.json │ ├── object_storage_bucket_access_get.json │ ├── object_storage_bucket_cert.json │ ├── object_storage_bucket_contents.json │ ├── object_storage_bucket_create.json │ ├── object_storage_bucket_get.json │ ├── object_storage_bucket_list.json │ ├── object_storage_buckets_object_list.json │ ├── object_storage_cluster_get.json │ ├── object_storage_cluster_list.json │ ├── object_storage_endpoints_list.json │ ├── object_storage_key_create.json │ ├── object_storage_key_get.json │ ├── object_storage_key_list.json │ ├── object_storage_key_list_by_region.json │ ├── object_storage_key_update.json │ ├── object_storage_object_acl_get.json │ ├── object_storage_object_acl_update.json │ ├── object_storage_object_url_create.json │ ├── object_storage_quotas_get.json │ ├── object_storage_quotas_list.json │ ├── object_storage_quotas_usage_get.json │ ├── placement_group_assign.json │ ├── placement_group_create.json │ ├── placement_group_unassign.json │ ├── placement_group_update.json │ ├── placement_groups_get.json │ ├── placement_groups_list.json │ ├── postgresql_database_config_get.json │ ├── postgresql_database_create.json │ ├── postgresql_database_credentials_get.json │ ├── postgresql_database_get.json │ ├── postgresql_database_ssl_get.json │ ├── postgresql_database_update.json │ ├── postgresql_databases_list.json │ ├── profile_apps_get.json │ ├── profile_apps_list.json │ ├── profile_devices_get.json │ ├── profile_devices_list.json │ ├── profile_get.json │ ├── profile_grants_list.json │ ├── profile_login_get.json │ ├── profile_logins_list.json │ ├── profile_preferences_get.json │ ├── profile_preferences_update.json │ ├── profile_security_question_answer.json │ ├── profile_security_question_list.json │ ├── profile_sshkey_create.json │ ├── profile_sshkey_get.json │ ├── profile_sshkey_update.json │ ├── profile_sshkeys_list.json │ ├── profile_token_create.json │ ├── profile_token_get.json │ ├── profile_token_update.json │ ├── profile_tokens_list.json │ ├── profile_two_factor_enable.json │ ├── profile_two_factor_secret_create.json │ ├── profile_update.json │ ├── region_availability_get.json │ ├── region_get.json │ ├── regions_availability_list.json │ ├── regions_list.json │ ├── stackscript_get.json │ ├── stackscript_revision.json │ ├── stackscripts_list.json │ ├── support_ticket_get.json │ ├── support_ticket_list.json │ ├── tag_create.json │ ├── tagged_objects_list.json │ ├── tags_list.json │ ├── vlan_get_ipam_address.json │ ├── vlans_list.json │ ├── volume_attach.json │ ├── volume_create.json │ ├── volume_get.json │ ├── volume_types_list.json │ ├── volume_update.json │ ├── volumes_list.json │ ├── vpc_create.json │ ├── vpc_get.json │ ├── vpc_ips_list.json │ ├── vpc_list.json │ ├── vpc_specific_ips_list.json │ ├── vpc_subnet_create.json │ ├── vpc_subnet_get.json │ ├── vpc_subnet_update.json │ ├── vpc_subnets_list.json │ └── vpc_update.json │ ├── images_test.go │ ├── instance_backup_test.go │ ├── instance_config_interfaces_test.go │ ├── instance_config_test.go │ ├── instance_disks_test.go │ ├── instance_firewall_test.go │ ├── instance_ip_test.go │ ├── instance_nodebalancers_test.go │ ├── instance_stats_test.go │ ├── instance_test.go │ ├── instance_volume_test.go │ ├── lke_cluster_control_plane_acl_test.go │ ├── lke_cluster_pool_test.go │ ├── lke_clusters_test.go │ ├── lke_node_pools_test.go │ ├── lke_types_test.go │ ├── longview_subscriptions_test.go │ ├── longview_test.go │ ├── monitor_dashboards_test.go │ ├── monitor_services_metrics_definition_test.go │ ├── monitor_services_test.go │ ├── monitor_services_token_test.go │ ├── mysql_test.go │ ├── network_ips_test.go │ ├── network_ipv6_pools_test.go │ ├── network_ranges_test.go │ ├── network_reserved_ips_test.go │ ├── nodebalancer_config_test.go │ ├── nodebalancer_configs_test.go │ ├── nodebalancer_firewalls_test.go │ ├── nodebalancer_node_test.go │ ├── nodebalancer_stats_test.go │ ├── nodebalancer_test.go │ ├── nodebalancer_types_test.go │ ├── nodebalancers_test.go │ ├── object_storage_bucket_cert_test.go │ ├── object_storage_bucket_test.go │ ├── object_storage_cluster_test.go │ ├── object_storage_endpoint_test.go │ ├── object_storage_key_test.go │ ├── object_storage_object_test.go │ ├── object_storage_quota_test.go │ ├── object_storage_test.go │ ├── placement_group_test.go │ ├── postgres_test.go │ ├── profile_apps_test.go │ ├── profile_devices_test.go │ ├── profile_grants_list_test.go │ ├── profile_login_test.go │ ├── profile_phone_number_test.go │ ├── profile_preferences_test.go │ ├── profile_security_questions_test.go │ ├── profile_sshkey_test.go │ ├── profile_test.go │ ├── profile_tfa_test.go │ ├── profile_token_test.go │ ├── region_test.go │ ├── stackscripts_test.go │ ├── support_test.go │ ├── tag_test.go │ ├── types_test.go │ ├── util_test.go │ ├── vlan_test.go │ ├── volume_test.go │ ├── volume_types_test.go │ ├── vpc_ips_test.go │ ├── vpc_subnets_test.go │ └── vpc_test.go ├── types.go ├── version.go ├── vlans.go ├── volumes.go ├── volumes_types.go ├── vpc.go ├── vpc_ips.go ├── vpc_subnet.go └── waitfor.go /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | The [Linode Community](https://www.linode.com/community/questions/) is a great place to get additional support. 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | name: Enhancement 2 | description: Request a feature 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: What would you like this feature to do in detail? 11 | validations: 12 | required: true 13 | 14 | - type: textarea 15 | id: example 16 | attributes: 17 | label: Example Code 18 | description: How would you use this feature in some example code? 19 | placeholder: | 20 | ```go 21 | var := linodego.NewFeature() 22 | ``` 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/help.yml: -------------------------------------------------------------------------------- 1 | name: Help 2 | description: You're pretty sure it's not a bug but you can't figure out why it's not working 3 | title: "[Help]: " 4 | labels: ["help wanted"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: What are you attempting to do, what error messages are you getting? 11 | validations: 12 | required: true 13 | 14 | - type: textarea 15 | id: code 16 | attributes: 17 | label: Attempted Code 18 | description: If your code is longer than a small snipit please use Gists 19 | placeholder: | 20 | ```go 21 | var := linodego.NewFeature() 22 | ``` 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 📝 Description 2 | 3 | **What does this PR do and why is this change necessary?** 4 | 5 | ## ✔️ How to Test 6 | 7 | **What are the steps to reproduce the issue or verify the changes?** 8 | 9 | **How do I run the relevant unit/integration tests?** 10 | 11 | ## 📷 Preview 12 | 13 | **If applicable, include a screenshot or code snippet of this change. Otherwise, please remove this section.** -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore-for-release 5 | categories: 6 | - title: 📋 New Project 7 | labels: 8 | - project 9 | - title: ⚠️ Breaking Change 10 | labels: 11 | - breaking-change 12 | - title: 🐛 Bug Fixes 13 | labels: 14 | - bugfix 15 | - title: 🚀 New Features 16 | labels: 17 | - new-feature 18 | - title: 💡 Improvements 19 | labels: 20 | - improvement 21 | - title: 🧪 Testing Improvements 22 | labels: 23 | - testing 24 | - title: ⚙️ Repo/CI Improvements 25 | labels: 26 | - repo-ci-improvement 27 | - title: 📖 Documentation 28 | labels: 29 | - documentation 30 | - title: 📦 Dependency Updates 31 | labels: 32 | - dependencies 33 | - title: Other Changes 34 | labels: 35 | - "*" 36 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL Advanced" 2 | 3 | on: 4 | push: 5 | branches: [ "dev", "main", "proj/*" ] 6 | pull_request: 7 | branches: [ "dev", "main", "proj/*" ] 8 | schedule: 9 | - cron: '39 0 * * 6' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze (${{ matrix.language }}) 14 | runs-on: ubuntu-latest 15 | permissions: 16 | security-events: write 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | - language: go 23 | build-mode: autobuild 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | - name: Initialize CodeQL 29 | uses: github/codeql-action/init@v3 30 | with: 31 | languages: ${{ matrix.language }} 32 | build-mode: ${{ matrix.build-mode }} 33 | queries: security-and-quality 34 | 35 | - name: Perform CodeQL Analysis 36 | uses: github/codeql-action/analyze@v3 37 | with: 38 | category: "/language:${{matrix.language}}" 39 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: labeler 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | paths: 8 | - '.github/labels.yml' 9 | - '.github/workflows/labeler.yml' 10 | pull_request: 11 | paths: 12 | - '.github/labels.yml' 13 | - '.github/workflows/labeler.yml' 14 | 15 | jobs: 16 | labeler: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - 20 | name: Checkout 21 | uses: actions/checkout@v4 22 | - 23 | name: Run Labeler 24 | uses: crazy-max/ghaction-github-labeler@24d110aa46a59976b8a7f35518cb7f14f434c916 25 | with: 26 | github-token: ${{ secrets.GITHUB_TOKEN }} 27 | yaml-file: .github/labels.yml 28 | dry-run: ${{ github.event_name == 'pull_request' }} 29 | exclude: | 30 | help* 31 | *issue 32 | -------------------------------------------------------------------------------- /.github/workflows/release-cross-repo-test.yml: -------------------------------------------------------------------------------- 1 | name: Release Terraform cross repository test 2 | 3 | on: 4 | workflow_dispatch: # Manual trigger 5 | 6 | jobs: 7 | terraform_integration_test: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: checkout terraform repo 11 | uses: actions/checkout@v4 12 | with: 13 | repository: linode/terraform-provider-linode 14 | fetch-depth: 0 15 | submodules: 'recursive' 16 | 17 | - name: Set up Go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version: 'stable' 21 | - run: go version 22 | - run: make deps 23 | 24 | - name: Clone Repository 25 | uses: actions/checkout@v4 26 | with: 27 | path: linodego 28 | 29 | - name: Set up linodego 30 | run: | 31 | cd linodego 32 | linodego_dir=$(pwd) 33 | cd .. 34 | go mod edit -replace github.com/linode/linodego=$linodego_dir 35 | go mod tidy 36 | 37 | - name: run tests 38 | run: | 39 | make test-int 40 | env: 41 | LINODE_TOKEN: ${{ secrets.DX_LINODE_TOKEN }} 42 | -------------------------------------------------------------------------------- /.github/workflows/release-notify-slack.yml: -------------------------------------------------------------------------------- 1 | name: Notify Dev DX Channel on Release 2 | on: 3 | release: 4 | types: [published] 5 | workflow_dispatch: null 6 | 7 | jobs: 8 | notify: 9 | if: github.repository == 'linode/linodego' 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Notify Slack - Main Message 13 | uses: slackapi/slack-github-action@v2.1.0 14 | with: 15 | method: chat.postMessage 16 | token: ${{ secrets.SLACK_BOT_TOKEN }} 17 | payload: | 18 | channel: ${{ secrets.DEV_DX_SLACK_CHANNEL_ID }} 19 | blocks: 20 | - type: section 21 | text: 22 | type: mrkdwn 23 | text: "*New Release Published: _linodego_ <${{ github.event.release.html_url }}|${{ github.event.release.tag_name }}> is now live!* :tada:" -------------------------------------------------------------------------------- /.github/workflows/security_pr.yml: -------------------------------------------------------------------------------- 1 | name: Security Checks for Pull Requests 2 | on: 3 | pull_request: null 4 | 5 | jobs: 6 | dependency-review: 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: 'Checkout repository' 13 | uses: actions/checkout@v4 14 | - name: 'Dependency Review' 15 | uses: actions/dependency-review-action@v4 16 | with: 17 | comment-summary-in-pr: on-failure 18 | 19 | gosec_scan: 20 | runs-on: ubuntu-latest 21 | env: 22 | GO111MODULE: on 23 | steps: 24 | - name: Checkout Source 25 | uses: actions/checkout@v4 26 | 27 | - name: Run Gosec Security Scanner on root directory 28 | uses: securego/gosec@master 29 | with: 30 | # We need to temporarily exclude this as gosec doesn't 31 | # support using module files from subdirectories. 32 | args: -exclude-dir=k8s ./... 33 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Stale issue handler' 2 | on: 3 | workflow_dispatch: null 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | stale: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/stale@v9 12 | id: stale 13 | with: 14 | stale-issue-message: 'This issue is stale because it has been open 30 days with 15 | no activity. Remove stale label or comment or this will be closed in 16 | 5 days' 17 | days-before-stale: 30 18 | days-before-close: 5 19 | exempt-issue-labels: 'blocked,must,should,keep' 20 | - name: Print outputs 21 | run: echo ${{ join(steps.stale.outputs.*, ',') }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | 17 | # Common IDE paths 18 | .vscode/ 19 | .idea/ 20 | 21 | vendor/**/ 22 | .env 23 | coverage.txt 24 | go.work.sum 25 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "e2e_scripts"] 2 | path = e2e_scripts 3 | url = https://github.com/linode/dx-e2e-test-scripts 4 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @linode/dx 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Christopher "Chief" Najewicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /account_availability.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // AccountAvailability returns the resources availability in a region to an account. 8 | type AccountAvailability struct { 9 | // region id 10 | Region string `json:"region"` 11 | 12 | // the unavailable resources in a region to the customer 13 | Unavailable []string `json:"unavailable"` 14 | 15 | // the available resources in a region to the customer 16 | Available []string `json:"available"` 17 | } 18 | 19 | // ListAccountAvailabilities lists all regions and the resource availabilities to the account. 20 | func (c *Client) ListAccountAvailabilities(ctx context.Context, opts *ListOptions) ([]AccountAvailability, error) { 21 | return getPaginatedResults[AccountAvailability](ctx, c, "account/availability", opts) 22 | } 23 | 24 | // GetAccountAvailability gets the resources availability in a region to the customer. 25 | func (c *Client) GetAccountAvailability(ctx context.Context, regionID string) (*AccountAvailability, error) { 26 | b := formatAPIPath("account/availability/%s", regionID) 27 | return doGETRequest[AccountAvailability](ctx, c, b) 28 | } 29 | -------------------------------------------------------------------------------- /account_logins.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "time" 7 | 8 | "github.com/linode/linodego/internal/parseabletime" 9 | ) 10 | 11 | type Login struct { 12 | ID int `json:"id"` 13 | Datetime *time.Time `json:"datetime"` 14 | IP string `json:"ip"` 15 | Restricted bool `json:"restricted"` 16 | Username string `json:"username"` 17 | Status string `json:"status"` 18 | } 19 | 20 | func (c *Client) ListLogins(ctx context.Context, opts *ListOptions) ([]Login, error) { 21 | return getPaginatedResults[Login](ctx, c, "account/logins", opts) 22 | } 23 | 24 | // UnmarshalJSON implements the json.Unmarshaler interface 25 | func (i *Login) UnmarshalJSON(b []byte) error { 26 | type Mask Login 27 | 28 | l := struct { 29 | *Mask 30 | Datetime *parseabletime.ParseableTime `json:"datetime"` 31 | }{ 32 | Mask: (*Mask)(i), 33 | } 34 | 35 | if err := json.Unmarshal(b, &l); err != nil { 36 | return err 37 | } 38 | 39 | i.Datetime = (*time.Time)(l.Datetime) 40 | 41 | return nil 42 | } 43 | 44 | func (c *Client) GetLogin(ctx context.Context, loginID int) (*Login, error) { 45 | e := formatAPIPath("account/logins/%d", loginID) 46 | return doGETRequest[Login](ctx, c, e) 47 | } 48 | -------------------------------------------------------------------------------- /account_transfer.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import "context" 4 | 5 | // AccountTransfer represents an Account's network utilization for the current month. 6 | type AccountTransfer struct { 7 | Billable int `json:"billable"` 8 | Quota int `json:"quota"` 9 | Used int `json:"used"` 10 | 11 | RegionTransfers []AccountTransferRegion `json:"region_transfers"` 12 | } 13 | 14 | // AccountTransferRegion represents an Account's network utilization for the current month 15 | // in a given region. 16 | type AccountTransferRegion struct { 17 | ID string `json:"id"` 18 | Billable int `json:"billable"` 19 | Quota int `json:"quota"` 20 | Used int `json:"used"` 21 | } 22 | 23 | // GetAccountTransfer gets current Account's network utilization for the current month. 24 | func (c *Client) GetAccountTransfer(ctx context.Context) (*AccountTransfer, error) { 25 | return doGETRequest[AccountTransfer](ctx, c, "account/transfer") 26 | } 27 | -------------------------------------------------------------------------------- /base_types.go: -------------------------------------------------------------------------------- 1 | // This package contains various type-related base classes intended 2 | // to be used in composition across type structures in this project. 3 | 4 | package linodego 5 | 6 | // baseType is a base struct containing the core fields of a resource type 7 | // returned from the Linode API. 8 | type baseType[PriceType any, RegionPriceType any] struct { 9 | ID string `json:"id"` 10 | Label string `json:"label"` 11 | Price PriceType `json:"price"` 12 | RegionPrices []RegionPriceType `json:"region_prices"` 13 | Transfer int `json:"transfer"` 14 | } 15 | 16 | // baseTypePrice is a base struct containing the core fields of a resource type's 17 | // base price. 18 | type baseTypePrice struct { 19 | Hourly float64 `json:"hourly"` 20 | Monthly float64 `json:"monthly"` 21 | } 22 | 23 | // baseTypeRegionPrice is a base struct containing the core fields of a resource type's 24 | // region-specific price. 25 | type baseTypeRegionPrice struct { 26 | baseTypePrice 27 | 28 | ID string `json:"id"` 29 | } 30 | -------------------------------------------------------------------------------- /client_http.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "net/http" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | // Client is a wrapper around the Resty client 10 | // 11 | //nolint:unused 12 | type httpClient struct { 13 | //nolint:unused 14 | httpClient *http.Client 15 | //nolint:unused 16 | userAgent string 17 | //nolint:unused 18 | debug bool 19 | //nolint:unused 20 | retryConditionals []httpRetryConditional 21 | //nolint:unused 22 | retryAfter httpRetryAfter 23 | 24 | //nolint:unused 25 | pollInterval time.Duration 26 | 27 | //nolint:unused 28 | baseURL string 29 | //nolint:unused 30 | apiVersion string 31 | //nolint:unused 32 | apiProto string 33 | //nolint:unused 34 | selectedProfile string 35 | //nolint:unused 36 | loadedProfile string 37 | 38 | //nolint:unused 39 | configProfiles map[string]ConfigProfile 40 | 41 | // Fields for caching endpoint responses 42 | //nolint:unused 43 | shouldCache bool 44 | //nolint:unused 45 | cacheExpiration time.Duration 46 | //nolint:unused 47 | cachedEntries map[string]clientCacheEntry 48 | //nolint:unused 49 | cachedEntryLock *sync.RWMutex 50 | //nolint:unused 51 | logger httpLogger 52 | //nolint:unused 53 | onBeforeRequest []func(*http.Request) error 54 | //nolint:unused 55 | onAfterResponse []func(*http.Response) error 56 | } 57 | -------------------------------------------------------------------------------- /env.sample: -------------------------------------------------------------------------------- 1 | LINODE_TOKEN= 2 | LINODE_DEBUG=0 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/linode/linodego 2 | 3 | require ( 4 | github.com/go-resty/resty/v2 v2.16.5 5 | github.com/google/go-cmp v0.7.0 6 | github.com/google/go-querystring v1.1.0 7 | github.com/jarcoal/httpmock v1.4.0 8 | golang.org/x/net v0.40.0 9 | golang.org/x/oauth2 v0.30.0 10 | golang.org/x/text v0.25.0 11 | gopkg.in/ini.v1 v1.66.6 12 | ) 13 | 14 | require ( 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | github.com/stretchr/testify v1.10.0 18 | gopkg.in/yaml.v3 v3.0.1 // indirect 19 | ) 20 | 21 | go 1.23.0 22 | 23 | toolchain go1.24.1 24 | 25 | retract v1.0.0 // Accidental branch push 26 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.23.0 2 | 3 | toolchain go1.23.4 4 | 5 | use ( 6 | . 7 | ./k8s 8 | ./test 9 | ) 10 | -------------------------------------------------------------------------------- /instance_firewalls.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ListInstanceFirewalls returns a paginated list of Cloud Firewalls for linodeID 8 | func (c *Client) ListInstanceFirewalls(ctx context.Context, linodeID int, opts *ListOptions) ([]Firewall, error) { 9 | return getPaginatedResults[Firewall](ctx, c, formatAPIPath("linode/instances/%d/firewalls", linodeID), opts) 10 | } 11 | -------------------------------------------------------------------------------- /instance_nodebalancers.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ListInstanceNodeBalancers lists NodeBalancers that the provided instance is a node in 8 | func (c *Client) ListInstanceNodeBalancers(ctx context.Context, linodeID int, opts *ListOptions) ([]NodeBalancer, error) { 9 | return getPaginatedResults[NodeBalancer](ctx, c, formatAPIPath("linode/instances/%d/nodebalancers", linodeID), opts) 10 | } 11 | -------------------------------------------------------------------------------- /instance_volumes.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ListInstanceVolumes lists InstanceVolumes 8 | func (c *Client) ListInstanceVolumes(ctx context.Context, linodeID int, opts *ListOptions) ([]Volume, error) { 9 | return getPaginatedResults[Volume](ctx, c, formatAPIPath("linode/instances/%d/volumes", linodeID), opts) 10 | } 11 | -------------------------------------------------------------------------------- /internal/duration/duration_test.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestUnmarshalTimeRemaining(t *testing.T) { 9 | if *UnmarshalTimeRemaining(json.RawMessage("\"1:23\"")) != 83 { 10 | t.Errorf("Error parsing duration style time_remaining") 11 | } 12 | if UnmarshalTimeRemaining(json.RawMessage("null")) != nil { 13 | t.Errorf("Error parsing null time_remaining") 14 | } 15 | if *UnmarshalTimeRemaining(json.RawMessage("0")) != 0 { 16 | t.Errorf("Error parsing int style time_remaining") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /internal/parseabletime/parseable_time.go: -------------------------------------------------------------------------------- 1 | package parseabletime 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | const ( 8 | dateLayout = "2006-01-02T15:04:05" 9 | ) 10 | 11 | type ParseableTime time.Time 12 | 13 | func (p *ParseableTime) UnmarshalJSON(b []byte) error { 14 | t, err := time.Parse(`"`+dateLayout+`"`, string(b)) 15 | if err != nil { 16 | return err 17 | } 18 | 19 | *p = ParseableTime(t) 20 | 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /k8s/clientset.go: -------------------------------------------------------------------------------- 1 | package k8s 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | 7 | "github.com/linode/linodego" 8 | "k8s.io/client-go/kubernetes" 9 | "k8s.io/client-go/tools/clientcmd" 10 | "k8s.io/client-go/transport" 11 | ) 12 | 13 | // NewClientsetFromBytes builds a Clientset from a given Kubeconfig. 14 | // 15 | // Takes an optional transport.WrapperFunc to add request/response middleware to 16 | // api-server requests. 17 | func BuildClientsetFromConfig( 18 | lkeKubeconfig *linodego.LKEClusterKubeconfig, 19 | transportWrapper transport.WrapperFunc, 20 | ) (kubernetes.Interface, error) { 21 | kubeConfigBytes, err := base64.StdEncoding.DecodeString(lkeKubeconfig.KubeConfig) 22 | if err != nil { 23 | return nil, fmt.Errorf("failed to decode kubeconfig: %w", err) 24 | } 25 | 26 | restClientConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeConfigBytes) 27 | if err != nil { 28 | return nil, fmt.Errorf("failed to parse LKE cluster kubeconfig: %w", err) 29 | } 30 | 31 | if transportWrapper != nil { 32 | restClientConfig.Wrap(transportWrapper) 33 | } 34 | 35 | clientset, err := kubernetes.NewForConfig(restClientConfig) 36 | if err != nil { 37 | return nil, fmt.Errorf("failed to build k8s client from LKE cluster kubeconfig: %w", err) 38 | } 39 | return clientset, nil 40 | } 41 | -------------------------------------------------------------------------------- /lke_types.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // LKEType represents a single valid LKE type. 8 | // NOTE: This typically corresponds to the availability of a cluster's 9 | // control plane. 10 | type LKEType struct { 11 | baseType[LKETypePrice, LKETypeRegionPrice] 12 | } 13 | 14 | // LKETypePrice represents the base hourly and monthly prices 15 | // for an LKE type entry. 16 | type LKETypePrice struct { 17 | baseTypePrice 18 | } 19 | 20 | // LKETypeRegionPrice represents the regional hourly and monthly prices 21 | // for an LKE type entry. 22 | type LKETypeRegionPrice struct { 23 | baseTypeRegionPrice 24 | } 25 | 26 | // ListLKETypes lists LKE types. This endpoint is cached by default. 27 | func (c *Client) ListLKETypes(ctx context.Context, opts *ListOptions) ([]LKEType, error) { 28 | e := "lke/types" 29 | 30 | endpoint, err := generateListCacheURL(e, opts) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | if result := c.getCachedResponse(endpoint); result != nil { 36 | return result.([]LKEType), nil 37 | } 38 | 39 | response, err := getPaginatedResults[LKEType](ctx, c, e, opts) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | c.addCachedResponse(endpoint, response, &cacheExpiryTime) 45 | 46 | return response, nil 47 | } 48 | -------------------------------------------------------------------------------- /logger.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | //nolint:unused 9 | type httpLogger interface { 10 | Errorf(format string, v ...interface{}) 11 | Warnf(format string, v ...interface{}) 12 | Debugf(format string, v ...interface{}) 13 | } 14 | 15 | //nolint:unused 16 | type logger struct { 17 | l *log.Logger 18 | } 19 | 20 | //nolint:unused 21 | func createLogger() *logger { 22 | l := &logger{l: log.New(os.Stderr, "", log.Ldate|log.Lmicroseconds)} 23 | return l 24 | } 25 | 26 | //nolint:unused 27 | var _ httpLogger = (*logger)(nil) 28 | 29 | //nolint:unused 30 | func (l *logger) Errorf(format string, v ...interface{}) { 31 | l.output("ERROR RESTY "+format, v...) 32 | } 33 | 34 | //nolint:unused 35 | func (l *logger) Warnf(format string, v ...interface{}) { 36 | l.output("WARN RESTY "+format, v...) 37 | } 38 | 39 | //nolint:unused 40 | func (l *logger) Debugf(format string, v ...interface{}) { 41 | l.output("DEBUG RESTY "+format, v...) 42 | } 43 | 44 | //nolint:unused 45 | func (l *logger) output(format string, v ...interface{}) { //nolint:goprintffuncname 46 | if len(v) == 0 { 47 | l.l.Print(format) 48 | return 49 | } 50 | l.l.Printf(format, v...) 51 | } 52 | -------------------------------------------------------------------------------- /longview_subscriptions.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // LongviewSubscription represents a LongviewSubscription object 8 | type LongviewSubscription struct { 9 | ID string `json:"id"` 10 | Label string `json:"label"` 11 | ClientsIncluded int `json:"clients_included"` 12 | Price *LinodePrice `json:"price"` 13 | // UpdatedStr string `json:"updated"` 14 | // Updated *time.Time `json:"-"` 15 | } 16 | 17 | // ListLongviewSubscriptions lists LongviewSubscriptions 18 | func (c *Client) ListLongviewSubscriptions(ctx context.Context, opts *ListOptions) ([]LongviewSubscription, error) { 19 | return getPaginatedResults[LongviewSubscription](ctx, c, "longview/subscriptions", opts) 20 | } 21 | 22 | // GetLongviewSubscription gets the template with the provided ID 23 | func (c *Client) GetLongviewSubscription(ctx context.Context, templateID string) (*LongviewSubscription, error) { 24 | e := formatAPIPath("longview/subscriptions/%s", templateID) 25 | return doGETRequest[LongviewSubscription](ctx, c, e) 26 | } 27 | -------------------------------------------------------------------------------- /monitor_services.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // MonitorService represents a MonitorService object 8 | type MonitorService struct { 9 | Label string `json:"label"` 10 | ServiceType string `json:"service_type"` 11 | } 12 | 13 | // ListMonitorServices lists all the registered ACLP MonitorServices 14 | func (c *Client) ListMonitorServices(ctx context.Context, opts *ListOptions) ([]MonitorService, error) { 15 | return getPaginatedResults[MonitorService](ctx, c, "monitor/services", opts) 16 | } 17 | 18 | // ListMonitorServiceByType lists monitor services by a given service_type 19 | func (c *Client) ListMonitorServiceByType(ctx context.Context, serviceType string, opts *ListOptions) ([]MonitorService, error) { 20 | e := formatAPIPath("monitor/services/%s", serviceType) 21 | return getPaginatedResults[MonitorService](ctx, c, e, opts) 22 | } 23 | -------------------------------------------------------------------------------- /monitor_services_create_token.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // MonitorServiceToken represents a MonitorServiceToken object 8 | type MonitorServiceToken struct { 9 | Token string `json:"token"` 10 | } 11 | 12 | // Create token options. 13 | type MonitorTokenCreateOptions struct { 14 | // EntityIDs are expected to be type "any" as different service_types have different variable type for their entity_ids. For example, Linode has "int" entity_ids whereas object storage has "string" as entity_ids. 15 | EntityIDs []any `json:"entity_ids"` 16 | } 17 | 18 | // CreateMonitorServiceTokenForServiceType to create token for a given serviceType 19 | func (c *Client) CreateMonitorServiceTokenForServiceType(ctx context.Context, serviceType string, opts MonitorTokenCreateOptions) (*MonitorServiceToken, error) { 20 | e := formatAPIPath("monitor/services/%s/token", serviceType) 21 | return doPOSTRequest[MonitorServiceToken](ctx, c, e, opts) 22 | } 23 | -------------------------------------------------------------------------------- /network_pools.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ListIPv6Pools lists IPv6Pools 8 | func (c *Client) ListIPv6Pools(ctx context.Context, opts *ListOptions) ([]IPv6Range, error) { 9 | return getPaginatedResults[IPv6Range](ctx, c, "networking/ipv6/pools", opts) 10 | } 11 | 12 | // GetIPv6Pool gets the template with the provided ID 13 | func (c *Client) GetIPv6Pool(ctx context.Context, id string) (*IPv6Range, error) { 14 | e := formatAPIPath("networking/ipv6/pools/%s", id) 15 | return doGETRequest[IPv6Range](ctx, c, e) 16 | } 17 | -------------------------------------------------------------------------------- /nodebalancer_config_vpc.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // NodeBalancerVPCConfig objects represent a VPC config for a NodeBalancer 8 | // s 9 | // NOTE: NodeBalancer VPC support may not currently be available to all users. 10 | type NodeBalancerVPCConfig struct { 11 | ID int `json:"id"` 12 | IPv4Range string `json:"ipv4_range"` 13 | IPv6Range string `json:"ipv6_range,omitempty"` 14 | NodeBalancerID int `json:"nodebalancer_id"` 15 | SubnetID int `json:"subnet_id"` 16 | VPCID int `json:"vpc_id"` 17 | } 18 | 19 | // ListNodeBalancerVPCConfigs lists NodeBalancer VPC configs 20 | func (c *Client) ListNodeBalancerVPCConfigs(ctx context.Context, nodebalancerID int, opts *ListOptions) ([]NodeBalancerVPCConfig, error) { 21 | return getPaginatedResults[NodeBalancerVPCConfig](ctx, c, formatAPIPath("nodebalancers/%d/vpcs", nodebalancerID), opts) 22 | } 23 | 24 | // GetNodeBalancerVPCConfig gets the NodeBalancer VPC config with the specified id 25 | func (c *Client) GetNodeBalancerVPCConfig(ctx context.Context, nodebalancerID int, vpcID int) (*NodeBalancerVPCConfig, error) { 26 | e := formatAPIPath("nodebalancers/%d/vpcs/%d", nodebalancerID, vpcID) 27 | return doGETRequest[NodeBalancerVPCConfig](ctx, c, e) 28 | } 29 | -------------------------------------------------------------------------------- /nodebalancer_firewalls.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ListNodeBalancerFirewalls returns a paginated list of Cloud Firewalls for nodebalancerID 8 | func (c *Client) ListNodeBalancerFirewalls(ctx context.Context, nodebalancerID int, opts *ListOptions) ([]Firewall, error) { 9 | return getPaginatedResults[Firewall](ctx, c, formatAPIPath("nodebalancers/%d/firewalls", nodebalancerID), opts) 10 | } 11 | -------------------------------------------------------------------------------- /nodebalancer_stats.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // NodeBalancerStats represents a nodebalancer stats object 8 | type NodeBalancerStats struct { 9 | Title string `json:"title"` 10 | Data NodeBalancerStatsData `json:"data"` 11 | } 12 | 13 | // NodeBalancerStatsData represents a nodebalancer stats data object 14 | type NodeBalancerStatsData struct { 15 | Connections [][]float64 `json:"connections"` 16 | Traffic StatsTraffic `json:"traffic"` 17 | } 18 | 19 | // StatsTraffic represents a Traffic stats object 20 | type StatsTraffic struct { 21 | In [][]float64 `json:"in"` 22 | Out [][]float64 `json:"out"` 23 | } 24 | 25 | // GetNodeBalancerStats gets the template with the provided ID 26 | func (c *Client) GetNodeBalancerStats(ctx context.Context, nodebalancerID int) (*NodeBalancerStats, error) { 27 | e := formatAPIPath("nodebalancers/%d/stats", nodebalancerID) 28 | return doGETRequest[NodeBalancerStats](ctx, c, e) 29 | } 30 | -------------------------------------------------------------------------------- /nodebalancer_types.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // NodeBalancerType represents a single valid NodeBalancer type. 8 | type NodeBalancerType struct { 9 | baseType[NodeBalancerTypePrice, NodeBalancerTypeRegionPrice] 10 | } 11 | 12 | // NodeBalancerTypePrice represents the base hourly and monthly prices 13 | // for a NodeBalancer type entry. 14 | type NodeBalancerTypePrice struct { 15 | baseTypePrice 16 | } 17 | 18 | // NodeBalancerTypeRegionPrice represents the regional hourly and monthly prices 19 | // for a NodeBalancer type entry. 20 | type NodeBalancerTypeRegionPrice struct { 21 | baseTypeRegionPrice 22 | } 23 | 24 | // ListNodeBalancerTypes lists NodeBalancer types. This endpoint is cached by default. 25 | func (c *Client) ListNodeBalancerTypes(ctx context.Context, opts *ListOptions) ([]NodeBalancerType, error) { 26 | e := "nodebalancers/types" 27 | 28 | endpoint, err := generateListCacheURL(e, opts) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | if result := c.getCachedResponse(endpoint); result != nil { 34 | return result.([]NodeBalancerType), nil 35 | } 36 | 37 | response, err := getPaginatedResults[NodeBalancerType](ctx, c, e, opts) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | c.addCachedResponse(endpoint, response, &cacheExpiryTime) 43 | 44 | return response, nil 45 | } 46 | -------------------------------------------------------------------------------- /object_storage.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ObjectStorageTransfer is an object matching the response of object-storage/transfer 8 | type ObjectStorageTransfer struct { 9 | AmmountUsed int `json:"used"` 10 | } 11 | 12 | // CancelObjectStorage cancels and removes all object storage from the Account 13 | func (c *Client) CancelObjectStorage(ctx context.Context) error { 14 | return doPOSTRequestNoRequestResponseBody(ctx, c, "object-storage/cancel") 15 | } 16 | 17 | // GetObjectStorageTransfer returns the amount of outbound data transferred used by the Account 18 | func (c *Client) GetObjectStorageTransfer(ctx context.Context) (*ObjectStorageTransfer, error) { 19 | return doGETRequest[ObjectStorageTransfer](ctx, c, "object-storage/transfer") 20 | } 21 | -------------------------------------------------------------------------------- /object_storage_clusters.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // ObjectStorageCluster represents a linode object storage cluster object 8 | type ObjectStorageCluster struct { 9 | ID string `json:"id"` 10 | Domain string `json:"domain"` 11 | Status string `json:"status"` 12 | Region string `json:"region"` 13 | StaticSiteDomain string `json:"static_site_domain"` 14 | } 15 | 16 | // ListObjectStorageClusters lists ObjectStorageClusters 17 | func (c *Client) ListObjectStorageClusters(ctx context.Context, opts *ListOptions) ([]ObjectStorageCluster, error) { 18 | return getPaginatedResults[ObjectStorageCluster](ctx, c, "object-storage/clusters", opts) 19 | } 20 | 21 | // Deprecated: GetObjectStorageCluster uses a deprecated API endpoint. 22 | // GetObjectStorageCluster gets the template with the provided ID 23 | func (c *Client) GetObjectStorageCluster(ctx context.Context, clusterID string) (*ObjectStorageCluster, error) { 24 | e := formatAPIPath("object-storage/clusters/%s", clusterID) 25 | return doGETRequest[ObjectStorageCluster](ctx, c, e) 26 | } 27 | -------------------------------------------------------------------------------- /object_storage_endpoints.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import "context" 4 | 5 | // NotificationType constants start with Notification and include all known Linode API Notification Types. 6 | type ObjectStorageEndpointType string 7 | 8 | // NotificationType constants represent the actions that cause a Notification. New types may be added in the future. 9 | const ( 10 | ObjectStorageEndpointE0 ObjectStorageEndpointType = "E0" 11 | ObjectStorageEndpointE1 ObjectStorageEndpointType = "E1" 12 | ObjectStorageEndpointE2 ObjectStorageEndpointType = "E2" 13 | ObjectStorageEndpointE3 ObjectStorageEndpointType = "E3" 14 | ) 15 | 16 | // ObjectStorageEndpoint represents a linode object storage endpoint object 17 | type ObjectStorageEndpoint struct { 18 | Region string `json:"region"` 19 | S3Endpoint *string `json:"s3_endpoint"` 20 | EndpointType ObjectStorageEndpointType `json:"endpoint_type"` 21 | } 22 | 23 | // ListObjectStorageEndpoints lists all endpoints in all regions 24 | func (c *Client) ListObjectStorageEndpoints(ctx context.Context, opts *ListOptions) ([]ObjectStorageEndpoint, error) { 25 | return getPaginatedResults[ObjectStorageEndpoint](ctx, c, "object-storage/endpoints", opts) 26 | } 27 | -------------------------------------------------------------------------------- /pagination_test.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | ) 9 | 10 | func TestFlattenQueryStruct(t *testing.T) { 11 | type TestStruct struct { 12 | TestInt int `query:"test_int"` 13 | TestString string `query:"test_string"` 14 | TestString2 string `query:"test_string_2"` 15 | TestInt64 int64 `query:"test_int64"` 16 | TestIn64Ptr *int64 `query:"test_int64_ptr"` 17 | TestBool bool `query:"test_bool"` 18 | TestUntagged string 19 | } 20 | 21 | testInt64 := int64(789) 22 | 23 | inst := TestStruct{ 24 | TestInt: 123, 25 | TestString: "test+string", 26 | TestString2: "", 27 | TestInt64: 567, 28 | TestIn64Ptr: &testInt64, 29 | TestBool: true, 30 | TestUntagged: "cool", 31 | } 32 | 33 | expectedOutput := map[string]string{ 34 | "test_int": "123", 35 | "test_string": "test+string", 36 | "test_int64": "567", 37 | "test_int64_ptr": "789", 38 | "test_bool": "true", 39 | } 40 | 41 | result, err := flattenQueryStruct(inst) 42 | if err != nil { 43 | t.Fatal(err) 44 | } 45 | 46 | if !reflect.DeepEqual(result, expectedOutput) { 47 | t.Fatalf("diff in result: %v", cmp.Diff(result, expectedOutput)) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /profile_grants_list.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type GrantsListResponse = UserGrants 8 | 9 | func (c *Client) GrantsList(ctx context.Context) (*GrantsListResponse, error) { 10 | return doGETRequest[GrantsListResponse](ctx, c, "profile/grants") 11 | } 12 | -------------------------------------------------------------------------------- /profile_preferences.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | ) 7 | 8 | // ProfilePreferences represents the user's preferences. 9 | // The user preferences endpoints allow consumers of the API to store arbitrary JSON data, 10 | // such as a user's font size preference or preferred display name. 11 | type ProfilePreferences map[string]interface{} 12 | 13 | // UnmarshalJSON implements the json.Unmarshaler interface 14 | func (p *ProfilePreferences) UnmarshalJSON(b []byte) error { 15 | var data map[string]interface{} 16 | if err := json.Unmarshal(b, &data); err != nil { 17 | return err 18 | } 19 | 20 | *p = data 21 | return nil 22 | } 23 | 24 | // GetProfilePreferences retrieves the user preferences for the current User 25 | func (c *Client) GetProfilePreferences(ctx context.Context) (*ProfilePreferences, error) { 26 | return doGETRequest[ProfilePreferences](ctx, c, "profile/preferences") 27 | } 28 | 29 | // UpdateProfilePreferences updates the user's preferences with the provided data 30 | func (c *Client) UpdateProfilePreferences(ctx context.Context, opts ProfilePreferences) (*ProfilePreferences, error) { 31 | return doPUTRequest[ProfilePreferences](ctx, c, "profile/preferences", opts) 32 | } 33 | -------------------------------------------------------------------------------- /profile_security_questions.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type SecurityQuestion struct { 8 | ID int `json:"id"` 9 | Question string `json:"question"` 10 | Response string `json:"response"` 11 | } 12 | 13 | type SecurityQuestionsListResponse struct { 14 | SecurityQuestions []SecurityQuestion `json:"security_questions"` 15 | } 16 | 17 | type SecurityQuestionsAnswerQuestion struct { 18 | QuestionID int `json:"question_id"` 19 | Response string `json:"response"` 20 | } 21 | 22 | type SecurityQuestionsAnswerOptions struct { 23 | SecurityQuestions []SecurityQuestionsAnswerQuestion `json:"security_questions"` 24 | } 25 | 26 | // SecurityQuestionsList returns a collection of security questions and their responses, if any, for your User Profile. 27 | func (c *Client) SecurityQuestionsList(ctx context.Context) (*SecurityQuestionsListResponse, error) { 28 | return doGETRequest[SecurityQuestionsListResponse](ctx, c, "profile/security-questions") 29 | } 30 | 31 | // SecurityQuestionsAnswer adds security question responses for your User. 32 | func (c *Client) SecurityQuestionsAnswer(ctx context.Context, opts SecurityQuestionsAnswerOptions) error { 33 | return doPOSTRequestNoResponseBody(ctx, c, "profile/security-questions", opts) 34 | } 35 | -------------------------------------------------------------------------------- /scripts/update_fixtures_contains_specific_string.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import subprocess 3 | from pathlib import Path 4 | 5 | repo_dir = Path(__file__).parent.parent 6 | directory = repo_dir / Path("test/integration/fixtures") 7 | 8 | search_string = sys.argv[1] 9 | failed_tests = [] 10 | 11 | for file in directory.glob("*"): 12 | if file.is_file(): 13 | content = file.read_text() 14 | if search_string in content: 15 | print(f"Found {search_string} in {file}") 16 | test_case = file.name.split(".")[0] 17 | command = f"make ARGS=\"-run {test_case}\" fixtures" 18 | output = subprocess.run(command, shell=True, capture_output=True) 19 | if output.returncode == 0: 20 | print(f"Successfully ran '{command}'") 21 | else: 22 | print(f"Command {command} failed with error:") 23 | print(output.stderr.decode()) 24 | failed_tests.append(test_case) 25 | else: 26 | print(f"Did not find {search_string} in {file}") 27 | 28 | print(f"These fixture generations failed: {failed_tests}") 29 | -------------------------------------------------------------------------------- /scripts/verify-gomod-tidy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | go mod tidy 6 | 7 | if [[ `git status --porcelain` ]]; then 8 | echo 'go.mod needs updating' 9 | echo 'Please run "go mod tidy" to fix dependencies' 10 | exit 1 11 | fi 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test-int 2 | 3 | test-int: 4 | @LINODE_FIXTURE_MODE="play" \ 5 | LINODE_TOKEN="awesometokenawesometokenawesometoken" \ 6 | LINODE_API_VERSION="v4beta" \ 7 | GO111MODULE="on" \ 8 | go test -v ./integration $(TEST_ARGS) -timeout=$(TEST_TIMEOUT) 9 | 10 | .PHONY: test-unit 11 | 12 | test-unit: 13 | go test -v ./unit/... $(TEST_ARGS) 14 | 15 | .PHONY: test-smoke 16 | 17 | test-smoke: 18 | @LINODE_FIXTURE_MODE="record" \ 19 | LINODE_TOKEN=$(LINODE_TOKEN) \ 20 | LINODE_API_VERSION="v4beta" \ 21 | LINODE_URL="$(LINODE_URL)" \ 22 | GO111MODULE="on" \ 23 | go test -v -run smoke ./integration/... -timeout=$(TEST_TIMEOUT) 24 | -------------------------------------------------------------------------------- /test/integration/account_agreements_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestAccountAgreements_Get(t *testing.T) { 9 | client, fixtureTeardown := createTestClient(t, "fixtures/TestAccountAgreements_List") 10 | defer fixtureTeardown() 11 | 12 | _, err := client.GetAccountAgreements(context.Background()) 13 | if err != nil { 14 | t.Errorf("Error getting agreements, expected struct, got error %v", err) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/integration/account_availability_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | ) 9 | 10 | func TestAccountAvailability_List(t *testing.T) { 11 | client, teardown := createTestClient(t, "fixtures/TestAccountAvailability_List") 12 | defer teardown() 13 | 14 | availabilities, err := client.ListAccountAvailabilities(context.Background(), &linodego.ListOptions{}) 15 | if err != nil { 16 | t.Errorf("Error getting Account Availabilities, expected struct, got error %v", err) 17 | } 18 | 19 | if len(availabilities) == 0 { 20 | t.Errorf("Expected to see account availabilities returned.") 21 | } 22 | } 23 | 24 | func TestAccountAvailability_Get(t *testing.T) { 25 | client, teardown := createTestClient(t, "fixtures/TestAccountAvailability_Get") 26 | defer teardown() 27 | 28 | regionID := "us-east" 29 | availability, err := client.GetAccountAvailability(context.Background(), regionID) 30 | if err != nil { 31 | t.Errorf("Error getting Account Availability, expected struct, got error %v", err) 32 | } 33 | 34 | if availability.Region != regionID { 35 | t.Errorf("expected region ID to be %s; got %s", regionID, availability.Region) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/integration/account_child_test.go: -------------------------------------------------------------------------------- 1 | //go:build parent_child 2 | 3 | package integration 4 | 5 | import ( 6 | "context" 7 | "reflect" 8 | "testing" 9 | 10 | "github.com/google/go-cmp/cmp" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | // NOTE: These fixtures are expected to be run under a parent account. 15 | func TestAccountChild_basic(t *testing.T) { 16 | client, teardown := createTestClient(t, "fixtures/TestAccountChild_basic") 17 | defer teardown() 18 | 19 | childAccounts, err := client.ListChildAccounts(context.Background(), nil) 20 | require.NoError(t, err) 21 | require.Greater( 22 | t, 23 | len(childAccounts), 24 | 0, 25 | "number of child accounts should be > 0", 26 | ) 27 | 28 | childAccount, err := client.GetChildAccount(context.Background(), childAccounts[0].EUUID) 29 | require.NoError(t, err) 30 | require.True( 31 | t, 32 | reflect.DeepEqual(*childAccount, childAccounts[0]), 33 | "child accounts should be equal", 34 | cmp.Diff(*childAccount, childAccounts[0]), 35 | ) 36 | 37 | token, err := client.CreateChildAccountToken(context.Background(), childAccount.EUUID) 38 | require.NoError(t, err) 39 | require.Greater(t, len(token.Token), 0) 40 | } 41 | -------------------------------------------------------------------------------- /test/integration/account_logins_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestAccountLogins_List(t *testing.T) { 9 | client, teardown := createTestClient(t, "fixtures/TestAccountLogins_List") 10 | defer teardown() 11 | 12 | logins, err := client.ListLogins(context.Background(), nil) 13 | if err != nil { 14 | t.Errorf("Error getting Account Logins, expected struct, got error %v", err) 15 | } 16 | 17 | if len(logins) < 1 { 18 | t.Errorf("Expected to see at least one Account Login") 19 | } 20 | 21 | login := logins[0] 22 | 23 | response, err := client.GetLogin(context.Background(), login.ID) 24 | if err != nil { 25 | t.Errorf("Failed to get one Account Login: %v", err) 26 | } 27 | 28 | if response.Username != login.Username { 29 | t.Fatal("Recieved Account Login Username does not match source") 30 | } 31 | 32 | if response.Status != "successful" && response.Status != "failed" { 33 | t.Fatal("Recieved invalid Account Login Status") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/integration/account_maintenance_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | ) 9 | 10 | func TestAccountMaintenances_List(t *testing.T) { 11 | client, fixtureTeardown := createTestClient(t, "fixtures/TestAccountMaintenances_List") 12 | defer fixtureTeardown() 13 | 14 | listOpts := linodego.NewListOptions(0, "") 15 | _, err := client.ListMaintenances(context.Background(), listOpts) 16 | if err != nil { 17 | t.Errorf("Error listing maintenances, expected array, got error %v", err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/integration/account_notifications_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | ) 9 | 10 | func TestAccountNotifications_List(t *testing.T) { 11 | client, fixtureTeardown := createTestClient(t, "fixtures/TestAccountNotifications_List") 12 | defer fixtureTeardown() 13 | 14 | listOpts := linodego.NewListOptions(0, "") 15 | _, err := client.ListNotifications(context.Background(), listOpts) 16 | if err != nil { 17 | t.Errorf("Error listing notifications, expected array, got error %v", err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/integration/account_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestAccount_Get(t *testing.T) { 9 | client, teardown := createTestClient(t, "fixtures/TestAccount_Get") 10 | defer teardown() 11 | 12 | account, err := client.GetAccount(context.Background()) 13 | if err != nil { 14 | t.Errorf("Error getting Account, expected struct, got error %v", err) 15 | } 16 | 17 | if len(account.Email) < 1 { 18 | t.Error("Error accessing Account, expected Email") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/integration/account_transfer_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestAccountTransfer_Get(t *testing.T) { 11 | client, teardown := createTestClient(t, "fixtures/TestAccountTransfer_Get") 12 | defer teardown() 13 | 14 | transfer, err := client.GetAccountTransfer(context.Background()) 15 | require.NoError(t, err, "Error getting Account Transfer, expected struct") 16 | 17 | require.NotEqual(t, 0, transfer.Billable, "Expected non-zero value for Billable") 18 | require.NotEqual(t, 0, transfer.Quota, "Expected non-zero value for Quota") 19 | require.NotEqual(t, 0, transfer.Used, "Expected non-zero value for Used") 20 | 21 | require.NotEmpty(t, transfer.RegionTransfers, "Expected to see region transfers") 22 | 23 | for _, regionTransfer := range transfer.RegionTransfers { 24 | require.NotEmpty(t, regionTransfer.ID, "Expected region ID to be non-empty") 25 | require.NotEqual(t, 0, regionTransfer.Billable, "Expected non-zero value for Billable in region %s", regionTransfer.ID) 26 | require.NotEqual(t, 0, regionTransfer.Quota, "Expected non-zero value for Quota in region %s", regionTransfer.ID) 27 | require.NotEqual(t, 0, regionTransfer.Used, "Expected non-zero value for Used in region %s", regionTransfer.ID) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/integration/fixtures/TestAccountSettings.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | interactions: 3 | - request: 4 | body: "" 5 | form: {} 6 | headers: 7 | Accept: 8 | - application/json 9 | Content-Type: 10 | - application/json 11 | url: https://api.linode.com/v4beta/account/settings 12 | method: GET 13 | response: 14 | body: '{ 15 | "backups_enabled": true, 16 | "managed": true, 17 | "network_helper": true, 18 | "longview_subscription": "longview-3", 19 | "object_storage": "active" 20 | }' 21 | headers: 22 | Content-Type: 23 | - application/json 24 | status: 200 25 | code: 200 26 | duration: "" 27 | 28 | - request: 29 | body: '{"backups_enabled":false,"longview_subscription":"longview-10","network_helper":false}' 30 | form: {} 31 | headers: 32 | Accept: 33 | - application/json 34 | Content-Type: 35 | - application/json 36 | url: https://api.linode.com/v4beta/account/settings 37 | method: PUT 38 | response: 39 | body: '{ 40 | "backups_enabled": false, 41 | "managed": true, 42 | "network_helper": false, 43 | "longview_subscription": "longview-10", 44 | "object_storage": "active" 45 | }' 46 | headers: 47 | Content-Type: 48 | - application/json 49 | status: 200 50 | code: 200 51 | duration: "" 52 | -------------------------------------------------------------------------------- /test/integration/fixtures/TestIPv6Pool_Get.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | interactions: 3 | - request: 4 | body: "" 5 | form: {} 6 | headers: 7 | Accept: 8 | - application/json 9 | Content-Type: 10 | - application/json 11 | url: https://api.linode.com/v4beta/networking/ipv6/pools/1234::5678%2F32 12 | method: GET 13 | response: 14 | body: '{"range": "1234::5678/32", "region": "us-east", "route_target": "1234::5678/32"}' 15 | headers: 16 | Content-Type: 17 | - application/json 18 | status: 200 19 | code: 200 20 | duration: "" -------------------------------------------------------------------------------- /test/integration/fixtures/TestIPv6Pool_List.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | interactions: 3 | - request: 4 | body: "" 5 | form: {} 6 | headers: 7 | Accept: 8 | - application/json 9 | Content-Type: 10 | - application/json 11 | url: https://api.linode.com/v4beta/networking/ipv6/pools?page=1 12 | method: GET 13 | response: 14 | body: '{"data": [{"range": "1234::5678/32", "region": "us-east", "route_target": "1234::5678/32"}], "page": 1, "pages": 1, "results": 1}' 15 | headers: 16 | Content-Type: 17 | - application/json 18 | status: 200 19 | code: 200 20 | duration: "" -------------------------------------------------------------------------------- /test/integration/fixtures/TestLKEVersion_GetMissing.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1 3 | interactions: 4 | - request: 5 | body: "" 6 | form: {} 7 | headers: 8 | Accept: 9 | - application/json 10 | Content-Type: 11 | - application/json 12 | User-Agent: 13 | - linodego/dev https://github.com/linode/linodego 14 | url: https://api.linode.com/v4beta/lke/versions/does-not-exist 15 | method: GET 16 | response: 17 | body: '{"errors": [{"reason": "Not found"}]}' 18 | headers: 19 | Access-Control-Allow-Headers: 20 | - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter 21 | Access-Control-Allow-Methods: 22 | - HEAD, GET, OPTIONS, POST, PUT, DELETE 23 | Access-Control-Allow-Origin: 24 | - '*' 25 | Cache-Control: 26 | - private, max-age=0, s-maxage=0, no-cache, no-store 27 | Content-Length: 28 | - "37" 29 | Content-Type: 30 | - application/json 31 | Server: 32 | - nginx 33 | Vary: 34 | - Authorization, X-Filter 35 | X-Accepted-Oauth-Scopes: 36 | - lke:read_only 37 | X-Frame-Options: 38 | - DENY 39 | X-Oauth-Scopes: 40 | - '*' 41 | X-Ratelimit-Limit: 42 | - "400" 43 | status: 404 Not Found 44 | code: 404 45 | duration: "" 46 | -------------------------------------------------------------------------------- /test/integration/fixtures/TestObjectStorageObject_ACLConfig_Bucket_Delete.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1 3 | interactions: 4 | - request: 5 | body: "" 6 | form: {} 7 | headers: {} 8 | url: https://us-east-1.linodeobjects.com:443/go-bucket-test-def/test?Signature=q40b1QCD%2FE5YyfsAW%2Fl5vZNfiRs%3D&Expires=1736322799&AWSAccessKeyID=SANITIZED 9 | method: DELETE 10 | response: 11 | body: "" 12 | headers: 13 | Connection: 14 | - keep-alive 15 | X-Amz-Request-Id: 16 | - tx000003f312b97ed86260d-00677e2d87-f1a4821b-default 17 | status: 204 No Content 18 | code: 204 19 | duration: "" 20 | -------------------------------------------------------------------------------- /test/integration/fixtures/TestObjectStorageObject_ACLConfig_Bucket_Put.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1 3 | interactions: 4 | - request: 5 | body: testing123 6 | form: {} 7 | headers: 8 | Content-Type: 9 | - text/plain 10 | url: https://us-east-1.linodeobjects.com:443/go-bucket-test-def/test?Signature=UZqhNnak%2FwLVHy0HB2TW87rl%2Baw%3D&Expires=1736322791&AWSAccessKeyID=SANITIZED 11 | method: PUT 12 | response: 13 | body: "" 14 | headers: 15 | Accept-Ranges: 16 | - bytes 17 | Connection: 18 | - keep-alive 19 | Content-Length: 20 | - "0" 21 | Etag: 22 | - '"7f2ababa423061c509f4923dd04b6cf1"' 23 | X-Amz-Request-Id: 24 | - tx000003d8b04716d761fbb-00677e2d7f-ef83577d-default 25 | status: 200 OK 26 | code: 200 27 | duration: "" 28 | -------------------------------------------------------------------------------- /test/integration/lke_types_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestLKEType_List(t *testing.T) { 12 | client, teardown := createTestClient(t, "fixtures/TestLKEType_List") 13 | defer teardown() 14 | 15 | lkeTypes, err := client.ListLKETypes(context.Background(), nil) 16 | require.NoError(t, err) 17 | require.Greater(t, len(lkeTypes), 0) 18 | 19 | for _, lkeType := range lkeTypes { 20 | validateLKEType(t, lkeType) 21 | } 22 | } 23 | 24 | func validateLKEType( 25 | t *testing.T, 26 | lkeType linodego.LKEType, 27 | ) { 28 | require.NotEmpty(t, lkeType.ID) 29 | require.NotEmpty(t, lkeType.Label) 30 | 31 | // NOTE: We use >= 0 here because this is treated as an additional 32 | // cost on top of the base LKE cluster price, meaning SA has its 33 | // prices set to 0. 34 | require.GreaterOrEqual(t, lkeType.Price.Hourly, 0.0) 35 | require.GreaterOrEqual(t, lkeType.Price.Monthly, 0.0) 36 | require.GreaterOrEqual(t, lkeType.Transfer, 0) 37 | 38 | for _, regionPrice := range lkeType.RegionPrices { 39 | require.NotEmpty(t, regionPrice.ID) 40 | require.GreaterOrEqual(t, regionPrice.Hourly, 0.0) 41 | require.GreaterOrEqual(t, regionPrice.Monthly, 0.0) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/integration/network_pools_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestIPv6Pool_List(t *testing.T) { 11 | client, teardown := createTestClient(t, "fixtures/TestIPv6Pool_List") 12 | defer teardown() 13 | 14 | ipv6Pools, err := client.ListIPv6Pools(context.Background(), nil) 15 | require.NoError(t, err, "Error getting IPv6 Pools, expected struct") 16 | 17 | require.NotEmpty(t, ipv6Pools, "Expected to see IPv6 pools returned") 18 | 19 | require.Equal(t, "1234::5678/32", ipv6Pools[0].Range, "Expected IPv6 pool range '1234::5678/32'") 20 | } 21 | 22 | func TestIPv6Pool_Get(t *testing.T) { 23 | client, teardown := createTestClient(t, "fixtures/TestIPv6Pool_Get") 24 | defer teardown() 25 | 26 | ipv6Pool, err := client.GetIPv6Pool(context.Background(), "1234::5678/32") 27 | require.NoError(t, err, "Error getting IPv6 Pool, expected struct") 28 | 29 | require.Equal(t, "1234::5678/32", ipv6Pool.Range, "Expected IPv6 pool range '1234::5678/32'") 30 | require.Equal(t, "us-east", ipv6Pool.Region, "Expected IPv6 pool region 'us-east'") 31 | } 32 | -------------------------------------------------------------------------------- /test/integration/network_transfer_prices_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestNetworkTransferPrice_List(t *testing.T) { 12 | client, teardown := createTestClient(t, "fixtures/TestNetworkTransferPrice_List") 13 | defer teardown() 14 | 15 | prices, err := client.ListNetworkTransferPrices(context.Background(), nil) 16 | require.NoError(t, err) 17 | require.Greater(t, len(prices), 0) 18 | 19 | for _, price := range prices { 20 | validateNetworkTransferPrice(t, price) 21 | } 22 | } 23 | 24 | func validateNetworkTransferPrice( 25 | t *testing.T, 26 | price linodego.NetworkTransferPrice, 27 | ) { 28 | require.NotEmpty(t, price.ID) 29 | require.NotEmpty(t, price.Label) 30 | 31 | // NOTE: We do not check for monthly prices here because it is 32 | // explicitly set to null. 33 | require.Greater(t, price.Price.Hourly, 0.0) 34 | require.GreaterOrEqual(t, price.Transfer, 0) 35 | 36 | for _, regionPrice := range price.RegionPrices { 37 | require.NotEmpty(t, regionPrice.ID) 38 | require.Greater(t, regionPrice.Hourly, 0.0) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/integration/nodebalancer_firewalls_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestNodeBalancerFirewalls_List_smoke(t *testing.T) { 9 | client, nodebalancer, teardown, err := setupNodeBalancer(t, 10 | "fixtures/TestNodeBalancerFirewalls_List", nil) 11 | if err != nil { 12 | t.Error(err) 13 | } 14 | defer teardown() 15 | 16 | result, err := client.ListNodeBalancerFirewalls(context.Background(), nodebalancer.ID, nil) 17 | if err != nil { 18 | t.Errorf("Error listing Firewalls, expected struct, got error %v", err) 19 | } 20 | 21 | if len(result) == 0 { 22 | t.Errorf("Expected a list of Firewalls, but got none: %v", err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/integration/nodebalancer_stats_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/linode/linodego" 9 | ) 10 | 11 | func TestNodeBalancerStats_Get(t *testing.T) { 12 | client, nodebalancer, teardown, err := setupNodeBalancer(t, "fixtures/TestNodeBalancerStats_Get", nil) 13 | defer teardown() 14 | if err != nil { 15 | t.Error(err) 16 | } 17 | 18 | ticker := time.NewTicker(10 * time.Second) 19 | timer := time.NewTimer(120 * time.Second) 20 | defer ticker.Stop() 21 | 22 | poll: 23 | for { 24 | select { 25 | case <-ticker.C: 26 | _, err = client.GetNodeBalancerStats(context.Background(), nodebalancer.ID) 27 | if err != nil { 28 | // Possible that the call succeeded but that stats aren't available (HTTP: 4XX) 29 | if v, ok := err.(*linodego.Error); ok { 30 | if v.Code == 400 && v.Message == "Stats are unavailable at this time." { 31 | break poll 32 | } 33 | // Otherwise, let's call it fatal 34 | t.Fatal(err) 35 | } 36 | } 37 | if err == nil { // stats are now returning 38 | break poll 39 | } 40 | case <-timer.C: 41 | t.Fatal("Error getting stats, polling timed out") 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/integration/nodebalancer_types_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestNodeBalancerType_List(t *testing.T) { 12 | client, teardown := createTestClient(t, "fixtures/TestNodeBalancerType_List") 13 | defer teardown() 14 | 15 | nbTypes, err := client.ListNodeBalancerTypes(context.Background(), nil) 16 | require.NoError(t, err) 17 | require.Greater(t, len(nbTypes), 0) 18 | 19 | for _, nbType := range nbTypes { 20 | validateNodeBalancerType(t, nbType) 21 | } 22 | } 23 | 24 | func validateNodeBalancerType( 25 | t *testing.T, 26 | nbType linodego.NodeBalancerType, 27 | ) { 28 | require.NotEmpty(t, nbType.ID) 29 | require.NotEmpty(t, nbType.Label) 30 | 31 | require.Greater(t, nbType.Price.Hourly, 0.0) 32 | require.Greater(t, nbType.Price.Monthly, 0.0) 33 | require.GreaterOrEqual(t, nbType.Transfer, 0) 34 | 35 | for _, regionPrice := range nbType.RegionPrices { 36 | require.NotEmpty(t, regionPrice.ID) 37 | require.Greater(t, regionPrice.Hourly, 0.0) 38 | require.Greater(t, regionPrice.Monthly, 0.0) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/integration/object_storage_clusters_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestObjectStorageClusters_List(t *testing.T) { 9 | client, teardown := createTestClient(t, "fixtures/TestObjectStorageClusters_List") 10 | defer teardown() 11 | 12 | objectStorageClusters, err := client.ListObjectStorageClusters(context.Background(), nil) 13 | if err != nil { 14 | t.Errorf("Error listing objectStorageClusters, expected struct - error %v", err) 15 | } 16 | if len(objectStorageClusters) == 0 { 17 | t.Errorf("Expected a list of objectStorageClusters - %v", objectStorageClusters) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/integration/profile_logins_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestProfileLogins_List(t *testing.T) { 9 | client, teardown := createTestClient(t, "fixtures/TestProfileLogins_List") 10 | defer teardown() 11 | 12 | logins, err := client.ListProfileLogins(context.Background(), nil) 13 | if err != nil { 14 | t.Errorf("Error getting Profile Logins, expected struct, got error %v", err) 15 | } 16 | 17 | if len(logins) < 1 { 18 | t.Errorf("Expected to see at least one Profile Login") 19 | } 20 | 21 | login := logins[0] 22 | 23 | response, err := client.GetProfileLogin(context.Background(), login.ID) 24 | if err != nil { 25 | t.Errorf("Failed to get one Profile Login: %v", err) 26 | } 27 | 28 | if response.Username != login.Username { 29 | t.Fatal("Recieved Profile Login Username does not match source") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/integration/profile_security_question_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestSecurityQuestions_List(t *testing.T) { 11 | warnSensitiveTest(t) 12 | 13 | client, teardown := createTestClient(t, "fixtures/TestSecurityQuestions_List") 14 | defer teardown() 15 | 16 | questions, err := client.SecurityQuestionsList(context.Background()) 17 | require.NoError(t, err, "Error getting security questions, expected struct") 18 | 19 | require.NotEmpty(t, questions.SecurityQuestions, "Expected to see security questions returned") 20 | 21 | require.Equal(t, "What was the name of your first pet?", questions.SecurityQuestions[0].Question, "Expected question 'What was the name of your first pet?'") 22 | } 23 | -------------------------------------------------------------------------------- /test/integration/profile_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestProfile_Get_smoke(t *testing.T) { 9 | client, teardown := createTestClient(t, "fixtures/TestProfile_Get") 10 | defer teardown() 11 | 12 | i, err := client.GetProfile(context.Background()) 13 | if err != nil { 14 | t.Errorf("Error getting profile: %s", err) 15 | } 16 | if len(i.Email) < 1 { 17 | t.Errorf("Expected profile email") 18 | } 19 | } 20 | 21 | func TestProfile_Update(t *testing.T) { 22 | client, teardown := createTestClient(t, "fixtures/TestProfile_Update") 23 | defer teardown() 24 | 25 | profile, err := client.GetProfile(context.Background()) 26 | if err != nil { 27 | t.Errorf("Error getting profile: %s", err) 28 | } 29 | 30 | updateOpts := profile.GetUpdateOptions() 31 | if updateOpts.Email != profile.Email { 32 | t.Errorf("Expected matching Username from GetUpdateOptions, got: %v", updateOpts) 33 | } 34 | 35 | i, err := client.UpdateProfile(context.Background(), updateOpts) 36 | if err != nil { 37 | t.Errorf("Error updating profile: %s", err) 38 | } 39 | if i.Email != updateOpts.Email { 40 | t.Errorf("Expected profile email to be changed, but found %v", i) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/integration/regionsavailability_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestRegionsAvailability_List(t *testing.T) { 9 | client, teardown := createTestClient(t, "fixtures/TestRegionsAvailability_List") 10 | defer teardown() 11 | 12 | testFunc := func(retryT *TRetry) { 13 | regions, err := client.ListRegionsAvailability(context.Background(), nil) 14 | if err != nil { 15 | t.Errorf("Error listing regions availability, expected struct - error %v", err) 16 | } 17 | if len(regions) == 0 { 18 | t.Errorf("Expected a list of regions availability - %v", regions) 19 | } 20 | } 21 | 22 | retryStatement(t, 3, testFunc) 23 | } 24 | -------------------------------------------------------------------------------- /test/integration/stackscripts_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | ) 9 | 10 | func TestStackscripts_List_smoke(t *testing.T) { 11 | client, teardown := createTestClient(t, "fixtures/TestStackscripts_List") 12 | defer teardown() 13 | 14 | filterOpt := linodego.NewListOptions(1, "") 15 | stackscripts, err := client.ListStackscripts(context.Background(), filterOpt) 16 | if err != nil { 17 | t.Errorf("Error listing stackscripts, expected struct - error %v", err) 18 | } 19 | if len(stackscripts) == 0 { 20 | t.Errorf("Expected a list of public stackscripts - %v", stackscripts) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/integration/util_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "strconv" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func assertDateSet(t *testing.T, compared *time.Time) { 10 | emptyTime := time.Time{} 11 | if compared == nil || *compared == emptyTime { 12 | t.Errorf("Expected date to be set, got %v", compared) 13 | } 14 | } 15 | 16 | func assertSliceContains[T comparable](t *testing.T, slice []T, target T) { 17 | for _, v := range slice { 18 | if v == target { 19 | return 20 | } 21 | } 22 | 23 | t.Fatalf("value %v not found in slice", target) 24 | } 25 | 26 | func minInt(a, b int) int { 27 | if a < b { 28 | return a 29 | } 30 | return b 31 | } 32 | 33 | // return the current nanosecond in string type as a unique text. 34 | func getUniqueText() string { 35 | return strconv.FormatInt(time.Now().UnixNano(), 10) 36 | } 37 | -------------------------------------------------------------------------------- /test/integration/volume_types_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestVolumeType_List(t *testing.T) { 12 | client, teardown := createTestClient(t, "fixtures/TestVolumeType_List") 13 | defer teardown() 14 | 15 | volumeTypes, err := client.ListVolumeTypes(context.Background(), nil) 16 | require.NoError(t, err) 17 | require.Greater(t, len(volumeTypes), 0) 18 | 19 | for _, volumeType := range volumeTypes { 20 | validateVolumeType(t, volumeType) 21 | } 22 | } 23 | 24 | func validateVolumeType( 25 | t *testing.T, 26 | volumeType linodego.VolumeType, 27 | ) { 28 | require.NotEmpty(t, volumeType.ID) 29 | require.NotEmpty(t, volumeType.Label) 30 | 31 | require.Greater(t, volumeType.Price.Hourly, 0.0) 32 | require.Greater(t, volumeType.Price.Monthly, 0.0) 33 | require.GreaterOrEqual(t, volumeType.Transfer, 0) 34 | 35 | for _, regionPrice := range volumeType.RegionPrices { 36 | require.NotEmpty(t, regionPrice.ID) 37 | require.Greater(t, regionPrice.Hourly, 0.0) 38 | require.Greater(t, regionPrice.Monthly, 0.0) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/unit/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linode/linodego/43ce1508c292b0dbc765ef76a0bbc41d67d14c02/test/unit/.DS_Store -------------------------------------------------------------------------------- /test/unit/account_agreements_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/jarcoal/httpmock" 8 | "github.com/linode/linodego" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestAccountAgreements_Get(t *testing.T) { 13 | fixtureData, err := fixtures.GetFixture("account_agreements_get") 14 | assert.NoError(t, err) 15 | 16 | var base ClientBaseCase 17 | base.SetUp(t) 18 | defer base.TearDown(t) 19 | 20 | base.MockGet("account/agreements", fixtureData) 21 | 22 | agreements, err := base.Client.GetAccountAgreements(context.Background()) 23 | assert.NoError(t, err) 24 | 25 | assert.Equal(t, true, agreements.EUModel) 26 | assert.Equal(t, true, agreements.PrivacyPolicy) 27 | assert.Equal(t, true, agreements.MasterServiceAgreement) 28 | } 29 | 30 | func TestAccountAgreements_Acknowledge(t *testing.T) { 31 | client := createMockClient(t) 32 | 33 | requestData := linodego.AccountAgreementsUpdateOptions{ 34 | EUModel: true, 35 | MasterServiceAgreement: true, 36 | PrivacyPolicy: true, 37 | } 38 | 39 | httpmock.RegisterRegexpResponder("POST", mockRequestURL(t, "account/agreements"), 40 | mockRequestBodyValidate(t, requestData, nil)) 41 | 42 | if err := client.AcknowledgeAccountAgreements(context.Background(), requestData); err != nil { 43 | t.Fatal(err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/unit/account_maintenance_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestAccountMaintenances_List(t *testing.T) { 11 | fixtureData, err := fixtures.GetFixture("account_maintenance_list") 12 | assert.NoError(t, err) 13 | 14 | var base ClientBaseCase 15 | base.SetUp(t) 16 | defer base.TearDown(t) 17 | 18 | base.MockGet("account/maintenance", fixtureData) 19 | 20 | maintenances, err := base.Client.ListMaintenances(context.Background(), nil) 21 | if err != nil { 22 | t.Fatalf("Error listing maintenances: %v", err) 23 | } 24 | 25 | assert.Equal(t, 1, len(maintenances)) 26 | maintenance := maintenances[0] 27 | assert.Equal(t, 1234, maintenance.Entity.ID) 28 | assert.Equal(t, "demo-linode", maintenance.Entity.Label) 29 | assert.Equal(t, "Linode", maintenance.Entity.Type) 30 | assert.Equal(t, "https://api.linode.com/v4/linode/instances/{linodeId}", maintenance.Entity.URL) 31 | assert.Equal(t, "This maintenance will allow us to update the BIOS on the host's motherboard.", maintenance.Reason) 32 | assert.Equal(t, "started", maintenance.Status) 33 | assert.Equal(t, "reboot", maintenance.Type) 34 | } 35 | -------------------------------------------------------------------------------- /test/unit/account_payments_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "testing" 7 | 8 | "github.com/linode/linodego" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestAccountPayments_Create(t *testing.T) { 13 | fixtureData, err := fixtures.GetFixture("account_payment_create") 14 | assert.NoError(t, err) 15 | 16 | var base ClientBaseCase 17 | base.SetUp(t) 18 | defer base.TearDown(t) 19 | 20 | base.MockPost("account/payments", fixtureData) 21 | 22 | requestData := linodego.PaymentCreateOptions{ 23 | CVV: "123", 24 | USD: json.Number("120.50"), 25 | } 26 | 27 | payment, err := base.Client.CreatePayment(context.Background(), requestData) 28 | if err != nil { 29 | t.Fatalf("Error creating payment: %v", err) 30 | } 31 | 32 | assert.Equal(t, 123, payment.ID) 33 | assert.Equal(t, json.Number("120.50"), payment.USD) 34 | } 35 | -------------------------------------------------------------------------------- /test/unit/account_promo_credits_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestAccountPromoCredits_Add(t *testing.T) { 12 | fixtureData, err := fixtures.GetFixture("account_promo_credits_add_promo_code") 13 | assert.NoError(t, err) 14 | 15 | var base ClientBaseCase 16 | base.SetUp(t) 17 | defer base.TearDown(t) 18 | 19 | base.MockPost("account/promo-codes", fixtureData) 20 | 21 | requestData := linodego.PromoCodeCreateOptions{ 22 | PromoCode: "supercoolpromocode", 23 | } 24 | 25 | promoCode, err := base.Client.AddPromoCode(context.Background(), requestData) 26 | if err != nil { 27 | t.Fatalf("Error adding promo code: %v", err) 28 | } 29 | 30 | assert.Equal(t, "10.00", promoCode.CreditMonthlyCap) 31 | assert.Equal(t, "50.00", promoCode.CreditRemaining) 32 | assert.Equal(t, "Receive up to $10 off your services every month for 6 months! Unused credits will expire once this promotion period ends.", promoCode.Description) 33 | assert.Equal(t, "https://linode.com/10_a_month_promotion.svg", promoCode.ImageURL) 34 | assert.Equal(t, "all", promoCode.ServiceType) 35 | assert.Equal(t, "$10 off your Linode a month!", promoCode.Summary) 36 | assert.Equal(t, "10.00", promoCode.ThisMonthCreditRemaining) 37 | } 38 | -------------------------------------------------------------------------------- /test/unit/account_transfer_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestAccount_getTransfer(t *testing.T) { 11 | fixtureData, err := fixtures.GetFixture("account_transfer_get") 12 | assert.NoError(t, err) 13 | 14 | var base ClientBaseCase 15 | base.SetUp(t) 16 | defer base.TearDown(t) 17 | 18 | base.MockGet("account/transfer", fixtureData) 19 | 20 | transferInfo, err := base.Client.GetAccountTransfer(context.Background()) 21 | assert.NoError(t, err) 22 | 23 | assert.Equal(t, 0, transferInfo.Billable) 24 | assert.Equal(t, 9141, transferInfo.Quota) 25 | assert.Equal(t, 2, transferInfo.Used) 26 | 27 | assert.Len(t, transferInfo.RegionTransfers, 1) 28 | assert.Equal(t, "us-east", transferInfo.RegionTransfers[0].ID) 29 | assert.Equal(t, 0, transferInfo.RegionTransfers[0].Billable) 30 | assert.Equal(t, 5010, transferInfo.RegionTransfers[0].Quota) 31 | assert.Equal(t, 1, transferInfo.RegionTransfers[0].Used) 32 | } 33 | -------------------------------------------------------------------------------- /test/unit/fixtures/account_agreements_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "eu_model": true, 3 | "master_service_agreement": true, 4 | "privacy_policy": true 5 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_availability_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "available": [ 3 | "Linodes", 4 | "NodeBalancers" 5 | ], 6 | "region": "us-east", 7 | "unavailable": [ 8 | "Kubernetes", 9 | "Block Storage" 10 | ] 11 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_beta_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "This is an open public beta for an example feature.", 3 | "ended": null, 4 | "enrolled": "2023-09-11T00:00:00", 5 | "id": "example_open", 6 | "label": "Example Open Beta", 7 | "started": "2023-07-11T00:00:00" 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_beta_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "description": "This is an open public beta for an example feature.", 5 | "ended": null, 6 | "enrolled": "2023-09-11T00:00:00", 7 | "id": "example_open", 8 | "label": "Example Open Beta", 9 | "started": "2023-07-11T00:00:00" 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 1 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_child_create_token.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2024-05-01T00:01:01", 3 | "expiry": "2024-05-01T00:16:01", 4 | "id": 918, 5 | "label": "parent1_1234_2024-05-01T00:01:01", 6 | "scopes": "*", 7 | "token": "abcdefghijklmnop" 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_child_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "active_since": "2018-01-01T00:01:01", 3 | "address_1": "123 Main Street", 4 | "address_2": "Suite A", 5 | "balance": 200, 6 | "balance_uninvoiced": 145, 7 | "billing_source": "external", 8 | "capabilities": [ 9 | "Linodes", 10 | "NodeBalancers", 11 | "Block Storage", 12 | "Object Storage" 13 | ], 14 | "city": "San Diego", 15 | "company": "Acme", 16 | "country": "US", 17 | "credit_card": { 18 | "expiry": "11/2024", 19 | "last_four": "1111" 20 | }, 21 | "email": "john.smith@linode.com", 22 | "euuid": "A1BC2DEF-34GH-567I-J890KLMN12O34P56", 23 | "first_name": "John", 24 | "last_name": "Smith", 25 | "phone": "858-555-1212", 26 | "state": "CA", 27 | "tax_id": "ATU99999999", 28 | "zip": "92111-1234" 29 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_child_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "active_since": "2018-01-01T00:01:01", 5 | "address_1": "123 Main Street", 6 | "address_2": "Suite A", 7 | "balance": 200, 8 | "balance_uninvoiced": 145, 9 | "billing_source": "external", 10 | "capabilities": [ 11 | "Linodes", 12 | "NodeBalancers", 13 | "Block Storage", 14 | "Object Storage" 15 | ], 16 | "city": "San Diego", 17 | "company": "Acme", 18 | "country": "US", 19 | "credit_card": { 20 | "expiry": "11/2024", 21 | "last_four": "1111" 22 | }, 23 | "email": "john.smith@linode.com", 24 | "euuid": "A1BC2DEF-34GH-567I-J890KLMN12O34P56", 25 | "first_name": "John", 26 | "last_name": "Smith", 27 | "phone": "858-555-1212", 28 | "state": "CA", 29 | "tax_id": "ATU99999999", 30 | "zip": "92111-1234" 31 | } 32 | ], 33 | "page": 1, 34 | "pages": 1, 35 | "results": 1 36 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_events_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "ticket_create", 3 | "created": "2018-01-01T00:01:01", 4 | "duration": 300.56, 5 | "entity": { 6 | "id": 11111, 7 | "label": "Problem booting my Linode", 8 | "type": "ticket", 9 | "url": "/v4/support/tickets/11111" 10 | }, 11 | "id": 123, 12 | "message": "None", 13 | "percent_complete": null, 14 | "rate": null, 15 | "read": true, 16 | "secondary_entity": { 17 | "id": "linode/debian9", 18 | "label": "linode1234", 19 | "type": "linode", 20 | "url": "/v4/linode/instances/1234" 21 | }, 22 | "seen": true, 23 | "status": "failed", 24 | "time_remaining": null, 25 | "username": "exampleUser" 26 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_events_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "action": "ticket_create", 5 | "created": "2018-01-01T00:01:01", 6 | "duration": 300.56, 7 | "entity": { 8 | "id": 11111, 9 | "label": "Problem booting my Linode", 10 | "type": "ticket", 11 | "url": "/v4/support/tickets/11111" 12 | }, 13 | "id": 123, 14 | "message": "None", 15 | "percent_complete": null, 16 | "rate": null, 17 | "read": true, 18 | "secondary_entity": { 19 | "id": "linode/debian9", 20 | "label": "linode1234", 21 | "type": "linode", 22 | "url": "/v4/linode/instances/1234" 23 | }, 24 | "seen": true, 25 | "status": "failed", 26 | "time_remaining": null, 27 | "username": "exampleUser" 28 | } 29 | ], 30 | "page": 1, 31 | "pages": 1, 32 | "results": 1 33 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "active_promotions": [ 3 | { 4 | "credit_monthly_cap": "10.00", 5 | "credit_remaining": "50.00", 6 | "description": "Receive up to $10 off your services every month for 6 months! Unused credits will expire once this promotion period ends.", 7 | "expire_dt": "2018-01-31T23:59:59", 8 | "image_url": "https://linode.com/10_a_month_promotion.svg", 9 | "service_type": "all", 10 | "summary": "$10 off your Linode a month!", 11 | "this_month_credit_remaining": "10.00" 12 | } 13 | ], 14 | "active_since": "2018-01-01T00:01:01", 15 | "address_1": "123 Main Street", 16 | "address_2": "Suite A", 17 | "balance": 200, 18 | "balance_uninvoiced": 145, 19 | "billing_source": "akamai", 20 | "capabilities": [ 21 | "Linodes", 22 | "NodeBalancers", 23 | "Block Storage", 24 | "Object Storage", 25 | "Placement Groups", 26 | "Block Storage Encryption" 27 | ], 28 | "city": "Philadelphia", 29 | "company": "Linode LLC", 30 | "country": "US", 31 | "credit_card": { 32 | "expiry": "11/2022", 33 | "last_four": "1111" 34 | }, 35 | "email": "john.smith@linode.com", 36 | "euuid": "E1AF5EEC-526F-487D-B317EBEB34C87D71", 37 | "first_name": "John", 38 | "last_name": "Smith", 39 | "phone": "215-555-1212", 40 | "state": "PA", 41 | "tax_id": "ATU99999999", 42 | "zip": "19102-1234" 43 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_invoice_items_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "amount": 20.2, 5 | "from": "2018-01-01T00:01:01", 6 | "label": "Linode 123", 7 | "quantity": 4, 8 | "region": "us-west", 9 | "tax": 1.25, 10 | "to": "2018-01-31T11:59:59", 11 | "total": 21.45, 12 | "type": "hourly", 13 | "unit_price": 5.05 14 | } 15 | ], 16 | "page": 1, 17 | "pages": 1, 18 | "results": 1 19 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_invoices_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "billing_source": "linode", 3 | "date": "2018-01-01T00:01:01", 4 | "id": 123, 5 | "label": "Invoice", 6 | "subtotal": 120.25, 7 | "tax": 12.25, 8 | "tax_summary": [ 9 | { 10 | "name": "PA STATE TAX", 11 | "tax": 12.25 12 | } 13 | ], 14 | "total": 132.5 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_invoices_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "billing_source": "linode", 5 | "date": "2018-01-01T00:01:01", 6 | "id": 123, 7 | "label": "Invoice", 8 | "subtotal": 120.25, 9 | "tax": 12.25, 10 | "tax_summary": [ 11 | { 12 | "name": "PA STATE TAX", 13 | "tax": 12.25 14 | } 15 | ], 16 | "total": 132.5 17 | } 18 | ], 19 | "page": 1, 20 | "pages": 1, 21 | "results": 1 22 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_logins_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "datetime": "2018-01-01T00:01:01", 3 | "id": 1234, 4 | "ip": "192.0.2.0", 5 | "restricted": true, 6 | "status": "successful", 7 | "username": "example_user" 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_logins_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "datetime": "2018-01-01T00:01:01", 5 | "id": 1234, 6 | "ip": "192.0.2.0", 7 | "restricted": true, 8 | "status": "successful", 9 | "username": "example_user" 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 1 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_maintenance_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "entity": { 5 | "id": 1234, 6 | "label": "demo-linode", 7 | "type": "Linode", 8 | "url": "https://api.linode.com/v4/linode/instances/{linodeId}" 9 | }, 10 | "reason": "This maintenance will allow us to update the BIOS on the host's motherboard.", 11 | "status": "started", 12 | "type": "reboot", 13 | "when": "2020-07-09T00:01:01" 14 | } 15 | ], 16 | "page": 1, 17 | "pages": 1, 18 | "results": 1 19 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_notifications_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "body": null, 5 | "entity": { 6 | "id": 3456, 7 | "label": "Linode not booting.", 8 | "type": "ticket", 9 | "url": "/support/tickets/3456" 10 | }, 11 | "label": "You have an important ticket open!", 12 | "message": "You have an important ticket open!", 13 | "severity": "major", 14 | "type": "ticket_important", 15 | "until": null, 16 | "when": null 17 | } 18 | ], 19 | "page": 1, 20 | "pages": 1, 21 | "results": 1 22 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_oauth_client_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2737bf16b39ab5d7b4a1", 3 | "label": "Test_Client_1", 4 | "public": false, 5 | "redirect_uri": "https://example.org/oauth/callback", 6 | "secret": "", 7 | "status": "active", 8 | "thumbnail_url": "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_oauth_client_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2737bf16b39ab5d7b4a1", 3 | "label": "Test_Client_1", 4 | "public": false, 5 | "redirect_uri": "https://example.org/oauth/callback", 6 | "secret": "", 7 | "status": "active", 8 | "thumbnail_url": "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_oauth_client_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "2737bf16b39ab5d7b4a1", 5 | "label": "Test_Client_1", 6 | "public": false, 7 | "redirect_uri": "https://example.org/oauth/callback", 8 | "secret": "", 9 | "status": "active", 10 | "thumbnail_url": "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" 11 | } 12 | ], 13 | "page": 1, 14 | "pages": 1, 15 | "results": 1 16 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_oauth_client_reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2737bf16b39ab5d7b4a1", 3 | "label": "Test_Client_1", 4 | "public": false, 5 | "redirect_uri": "https://example.org/oauth/callback", 6 | "secret": "", 7 | "status": "active", 8 | "thumbnail_url": "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_oauth_client_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2737bf16b39ab5d7b4a1", 3 | "label": "Test_Client_1_Updated", 4 | "public": true, 5 | "redirect_uri": "https://example_updated.org/oauth/callback", 6 | "secret": "", 7 | "status": "active", 8 | "thumbnail_url": "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_payment_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "date": "2018-01-15T00:01:01", 3 | "id": 123, 4 | "usd": "120.50" 5 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_payment_methods_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-15T00:01:01", 3 | "data": { 4 | "card_type": "Discover", 5 | "expiry": "06/2022", 6 | "last_four": "1234" 7 | }, 8 | "id": 123, 9 | "is_default": true, 10 | "type": "credit_card" 11 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_payment_methods_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created": "2018-01-15T00:01:01", 5 | "data": { 6 | "card_type": "Discover", 7 | "expiry": "06/2022", 8 | "last_four": "1234" 9 | }, 10 | "id": 123, 11 | "is_default": true, 12 | "type": "credit_card" 13 | } 14 | ], 15 | "page": 1, 16 | "pages": 1, 17 | "results": 1 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_promo_credits_add_promo_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "credit_monthly_cap": "10.00", 3 | "credit_remaining": "50.00", 4 | "description": "Receive up to $10 off your services every month for 6 months! Unused credits will expire once this promotion period ends.", 5 | "expire_dt": "2018-01-31T23:59:59", 6 | "image_url": "https://linode.com/10_a_month_promotion.svg", 7 | "service_type": "all", 8 | "summary": "$10 off your Linode a month!", 9 | "this_month_credit_remaining": "10.00" 10 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_service_transfers_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2021-02-11T16:37:03", 3 | "entities": { 4 | "linodes": [ 5 | 111, 6 | 222 7 | ] 8 | }, 9 | "expiry": "2021-02-12T16:37:03", 10 | "is_sender": true, 11 | "status": "pending", 12 | "token": "123E4567-E89B-12D3-A456-426614174000", 13 | "updated": "2021-02-11T16:37:03" 14 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_service_transfers_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created": "2021-02-11T16:37:03", 5 | "entities": { 6 | "linodes": [ 7 | 111, 8 | 222 9 | ] 10 | }, 11 | "expiry": "2021-02-12T16:37:03", 12 | "is_sender": true, 13 | "status": "pending", 14 | "token": "123E4567-E89B-12D3-A456-426614174000", 15 | "updated": "2021-02-11T16:37:03" 16 | } 17 | ], 18 | "page": 1, 19 | "pages": 1, 20 | "results": 1 21 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_service_transfers_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2021-02-11T16:37:03", 3 | "entities": { 4 | "linodes": [ 5 | 111, 6 | 222 7 | ] 8 | }, 9 | "expiry": "2021-02-12T16:37:03", 10 | "is_sender": true, 11 | "status": "pending", 12 | "token": "123E4567-E89B-12D3-A456-426614174000", 13 | "updated": "2021-02-11T16:37:03" 14 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_settings_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "managed": false, 3 | "network_helper": true, 4 | "longview_subscription": null, 5 | "backups_enabled": true, 6 | "object_storage": "active" 7 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_settings_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "managed": false, 3 | "network_helper": true, 4 | "longview_subscription": null, 5 | "backups_enabled": true, 6 | "object_storage": "active" 7 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_transfer_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "billable": 0, 3 | "quota": 9141, 4 | "region_transfers": [ 5 | { 6 | "billable": 0, 7 | "id": "us-east", 8 | "quota": 5010, 9 | "used": 1 10 | } 11 | ], 12 | "used": 2 13 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "active_promotions": [ 3 | { 4 | "credit_monthly_cap": "10.00", 5 | "credit_remaining": "50.00", 6 | "description": "Receive up to $10 off your services every month for 6 months! Unused credits will expire once this promotion period ends.", 7 | "expire_dt": "2018-01-31T23:59:59", 8 | "image_url": "https://linode.com/10_a_month_promotion.svg", 9 | "service_type": "all", 10 | "summary": "$10 off your Linode a month!", 11 | "this_month_credit_remaining": "10.00" 12 | } 13 | ], 14 | "active_since": "2018-01-01T00:01:01", 15 | "address_1": "123 Main Street", 16 | "address_2": "Suite A", 17 | "balance": 200, 18 | "balance_uninvoiced": 145, 19 | "billing_source": "akamai", 20 | "capabilities": [ 21 | "Linodes", 22 | "NodeBalancers", 23 | "Block Storage", 24 | "Object Storage", 25 | "Placement Groups", 26 | "Block Storage Encryption" 27 | ], 28 | "city": "Cambridge", 29 | "company": "Linode LLC", 30 | "country": "US", 31 | "credit_card": { 32 | "expiry": "11/2022", 33 | "last_four": "1111" 34 | }, 35 | "email": "john.smith@linode.com", 36 | "euuid": "E1AF5EEC-526F-487D-B317EBEB34C87D71", 37 | "first_name": "John", 38 | "last_name": "Smith", 39 | "phone": "215-555-1212", 40 | "state": "MA", 41 | "tax_id": "ATU99999999", 42 | "zip": "19102-1234" 43 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_users_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "email": "example_user@linode.com", 3 | "last_login": { 4 | "login_datetime": "2018-01-01T01:01:01", 5 | "status": "successful" 6 | }, 7 | "password_created": "2018-01-01T01:01:01", 8 | "restricted": true, 9 | "ssh_keys": [ 10 | "home-pc", 11 | "laptop" 12 | ], 13 | "tfa_enabled": true, 14 | "username": "example_user", 15 | "verified_phone_number": "+5555555555" 16 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_users_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "email": "jperez@linode.com", 3 | "last_login": { 4 | "login_datetime": "2018-01-01T01:01:01", 5 | "status": "successful" 6 | }, 7 | "password_created": "2018-01-01T01:01:01", 8 | "restricted": true, 9 | "ssh_keys": [ 10 | "home-pc", 11 | "laptop" 12 | ], 13 | "tfa_enabled": true, 14 | "user_type": "parent", 15 | "username": "jsmith", 16 | "verified_phone_number": "+5555555555" 17 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_users_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "email": "jperez@linode.com", 5 | "last_login": { 6 | "login_datetime": "2018-01-01T01:01:01", 7 | "status": "successful" 8 | }, 9 | "password_created": "2018-01-01T01:01:01", 10 | "restricted": true, 11 | "ssh_keys": [ 12 | "home-pc", 13 | "laptop" 14 | ], 15 | "tfa_enabled": true, 16 | "user_type": "parent", 17 | "username": "jsmith", 18 | "verified_phone_number": "+5555555555" 19 | } 20 | ], 21 | "page": 1, 22 | "pages": 1, 23 | "results": 1 24 | } -------------------------------------------------------------------------------- /test/unit/fixtures/account_users_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "email": "jkowalski@linode.com", 3 | "last_login": { 4 | "login_datetime": "2018-01-01T01:01:01", 5 | "status": "successful" 6 | }, 7 | "password_created": "2018-01-01T01:01:01", 8 | "restricted": true, 9 | "ssh_keys": [ 10 | "home-pc", 11 | "laptop" 12 | ], 13 | "tfa_enabled": true, 14 | "user_type": "parent", 15 | "username": "adevi", 16 | "verified_phone_number": "+5555555555" 17 | } -------------------------------------------------------------------------------- /test/unit/fixtures/database_engine_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "mysql-8", 3 | "engine": "mysql", 4 | "version": "8.0", 5 | "supported_versions": ["5.7", "8.0"] 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/database_maintenance_window.json: -------------------------------------------------------------------------------- 1 | { 2 | "day_of_week": 1, 3 | "duration": 2, 4 | "frequency": "weekly", 5 | "hour_of_day": 3 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/database_types_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "g6-standard-1", 5 | "label": "Standard Plan", 6 | "memory": 4096, 7 | "vcpus": 2, 8 | "disk": 80 9 | }, 10 | { 11 | "id": "g6-standard-2", 12 | "label": "High Performance Plan", 13 | "memory": 8192, 14 | "vcpus": 4, 15 | "disk": 160 16 | } 17 | ], 18 | "page": 1, 19 | "pages": 1, 20 | "results": 2 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/fixtures/database_unmarshal.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "status": "active", 4 | "label": "test-db", 5 | "region": "us-east", 6 | "type": "g6-standard-1", 7 | "engine": "mysql", 8 | "version": "8.0", 9 | "cluster_size": 3, 10 | "platform": "rdbms-default", 11 | "created": "2023-01-01T12:00:00" 12 | } 13 | -------------------------------------------------------------------------------- /test/unit/fixtures/databases_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "status": "active", 6 | "label": "test-db", 7 | "region": "us-east", 8 | "type": "g6-standard-1", 9 | "engine": "mysql", 10 | "version": "8.0", 11 | "cluster_size": 3, 12 | "platform": "rdbms-default", 13 | "created": "2023-01-01T12:00:00" 14 | } 15 | ], 16 | "page": 1, 17 | "pages": 1, 18 | "results": 1 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/domain_clone.json: -------------------------------------------------------------------------------- 1 | { 2 | "axfr_ips": [], 3 | "description": null, 4 | "domain": "linodego-domain-clone.com", 5 | "expire_sec": 300, 6 | "id": 1234, 7 | "master_ips": [], 8 | "refresh_sec": 300, 9 | "retry_sec": 300, 10 | "soa_email": "admin@example.org", 11 | "status": "active", 12 | "tags": [ 13 | "example tag", 14 | "another example" 15 | ], 16 | "ttl_sec": 300, 17 | "type": "master" 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domain_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "axfr_ips": [], 3 | "description": null, 4 | "domain": "example.org", 5 | "expire_sec": 300, 6 | "id": 1234, 7 | "master_ips": [], 8 | "refresh_sec": 300, 9 | "retry_sec": 300, 10 | "soa_email": "admin@example.org", 11 | "status": "active", 12 | "tags": [ 13 | "example tag", 14 | "another example" 15 | ], 16 | "ttl_sec": 300, 17 | "type": "master" 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domain_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "axfr_ips": [], 3 | "description": null, 4 | "domain": "example.org", 5 | "expire_sec": 300, 6 | "id": 1234, 7 | "master_ips": [], 8 | "refresh_sec": 300, 9 | "retry_sec": 300, 10 | "soa_email": "admin@example.org", 11 | "status": "active", 12 | "tags": [ 13 | "example tag", 14 | "another example" 15 | ], 16 | "ttl_sec": 300, 17 | "type": "master" 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domain_get_domainzonefile.json: -------------------------------------------------------------------------------- 1 | { 2 | "zone_file": [ 3 | "; example.com [123]", 4 | "$TTL 864000", 5 | "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", 6 | "@ NS ns1.linode.com.", 7 | "@ NS ns2.linode.com.", 8 | "@ NS ns3.linode.com.", 9 | "@ NS ns4.linode.com.", 10 | "@ NS ns5.linode.com." 11 | ] 12 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domain_import.json: -------------------------------------------------------------------------------- 1 | { 2 | "axfr_ips": [], 3 | "description": null, 4 | "domain": "example.org", 5 | "expire_sec": 300, 6 | "id": 1234, 7 | "master_ips": [], 8 | "refresh_sec": 300, 9 | "retry_sec": 300, 10 | "soa_email": "admin@example.org", 11 | "status": "active", 12 | "tags": [ 13 | "example tag", 14 | "another example" 15 | ], 16 | "ttl_sec": 300, 17 | "type": "master" 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domain_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "axfr_ips": [], 5 | "description": null, 6 | "domain": "example.org", 7 | "expire_sec": 300, 8 | "id": 1234, 9 | "master_ips": [], 10 | "refresh_sec": 300, 11 | "retry_sec": 300, 12 | "soa_email": "admin@example.org", 13 | "status": "active", 14 | "tags": [ 15 | "example tag", 16 | "another example" 17 | ], 18 | "ttl_sec": 300, 19 | "type": "master" 20 | } 21 | ], 22 | "page": 1, 23 | "pages": 1, 24 | "results": 1 25 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domain_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "axfr_ips": [], 3 | "description": null, 4 | "domain": "example.org", 5 | "expire_sec": 300, 6 | "id": 1234, 7 | "master_ips": [], 8 | "refresh_sec": 300, 9 | "retry_sec": 300, 10 | "soa_email": "admin@example.org", 11 | "status": "active", 12 | "tags": [ 13 | "example tag", 14 | "another example" 15 | ], 16 | "ttl_sec": 300, 17 | "type": "master" 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domainrecord_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "id": 123456, 4 | "name": "test", 5 | "port": 80, 6 | "priority": 50, 7 | "protocol": null, 8 | "service": null, 9 | "tag": null, 10 | "target": "192.0.2.0", 11 | "ttl_sec": 604800, 12 | "type": "A", 13 | "updated": "2018-01-01T00:01:01", 14 | "weight": 50 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domainrecord_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "id": 123456, 4 | "name": "test", 5 | "port": 80, 6 | "priority": 50, 7 | "protocol": null, 8 | "service": null, 9 | "tag": null, 10 | "target": "192.0.2.0", 11 | "ttl_sec": 604800, 12 | "type": "A", 13 | "updated": "2018-01-01T00:01:01", 14 | "weight": 50 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domainrecord_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created": "2018-01-01T00:01:01", 5 | "id": 123456, 6 | "name": "test", 7 | "port": 80, 8 | "priority": 50, 9 | "protocol": null, 10 | "service": null, 11 | "tag": null, 12 | "target": "192.0.2.0", 13 | "ttl_sec": 604800, 14 | "type": "A", 15 | "updated": "2018-01-01T00:01:01", 16 | "weight": 50 17 | } 18 | ], 19 | "page": 1, 20 | "pages": 1, 21 | "results": 1 22 | } -------------------------------------------------------------------------------- /test/unit/fixtures/domainrecord_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "id": 123456, 4 | "name": "test", 5 | "port": 80, 6 | "priority": 50, 7 | "protocol": null, 8 | "service": null, 9 | "tag": null, 10 | "target": "192.0.2.0", 11 | "ttl_sec": 604800, 12 | "type": "A", 13 | "updated": "2018-01-01T00:01:01", 14 | "weight": 50 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/firewall_device_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "entity": { 4 | "id": 123, 5 | "label": "my-linode", 6 | "type": "linode", 7 | "url": "/v4/linode/instances/123" 8 | }, 9 | "id": 123, 10 | "updated": "2018-01-02T00:01:01" 11 | } -------------------------------------------------------------------------------- /test/unit/fixtures/firewall_device_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "entity": { 4 | "id": 123, 5 | "label": "my-linode", 6 | "type": "linode", 7 | "url": "/v4/linode/instances/123" 8 | }, 9 | "id": 123, 10 | "updated": "2018-01-02T00:01:01" 11 | } -------------------------------------------------------------------------------- /test/unit/fixtures/firewall_device_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created": "2018-01-01T00:01:01", 5 | "entity": { 6 | "id": 123, 7 | "label": "my-linode", 8 | "type": "linode", 9 | "url": "/v4/linode/instances/123" 10 | }, 11 | "id": 456, 12 | "updated": "2018-01-02T00:01:01" 13 | }, 14 | { 15 | "created": "2018-01-01T00:01:01", 16 | "entity": { 17 | "id": 321, 18 | "label": "my-nodebalancer", 19 | "type": "nodebalancer", 20 | "url": "/v4/nodebalancers/123" 21 | }, 22 | "id": 654, 23 | "updated": "2018-01-02T00:01:01" 24 | } 25 | ], 26 | "page": 1, 27 | "pages": 1, 28 | "results": 1 29 | } -------------------------------------------------------------------------------- /test/unit/fixtures/firewall_rule_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "fingerprint": "997dd135", 3 | "inbound": [ 4 | { 5 | "action": "ACCEPT", 6 | "addresses": { 7 | "ipv4": [ 8 | "192.0.2.0/24", 9 | "198.51.100.2/32" 10 | ], 11 | "ipv6": [ 12 | "2001:DB8::/128" 13 | ] 14 | }, 15 | "description": "An example firewall rule description.", 16 | "label": "firewallrule123", 17 | "ports": "22-24, 80, 443", 18 | "protocol": "TCP" 19 | } 20 | ], 21 | "inbound_policy": "DROP", 22 | "outbound": [ 23 | { 24 | "action": "ACCEPT", 25 | "addresses": { 26 | "ipv4": [ 27 | "192.0.2.0/24", 28 | "198.51.100.2/32" 29 | ], 30 | "ipv6": [ 31 | "2001:DB8::/128" 32 | ] 33 | }, 34 | "description": "An example firewall rule description.", 35 | "label": "firewallrule123", 36 | "ports": "22-24, 80, 443", 37 | "protocol": "TCP" 38 | } 39 | ], 40 | "outbound_policy": "DROP", 41 | "version": 1 42 | } -------------------------------------------------------------------------------- /test/unit/fixtures/firewall_rule_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "fingerprint": "997dd135", 3 | "inbound": [ 4 | { 5 | "action": "ACCEPT", 6 | "addresses": { 7 | "ipv4": [ 8 | "192.0.2.0/24", 9 | "198.51.100.2/32" 10 | ], 11 | "ipv6": [ 12 | "2001:DB8::/128" 13 | ] 14 | }, 15 | "description": "An example firewall rule description.", 16 | "label": "firewallrule123", 17 | "ports": "22-24, 80, 443", 18 | "protocol": "TCP" 19 | } 20 | ], 21 | "inbound_policy": "DROP", 22 | "outbound": [ 23 | { 24 | "action": "ACCEPT", 25 | "addresses": { 26 | "ipv4": [ 27 | "192.0.2.0/24", 28 | "198.51.100.2/32" 29 | ], 30 | "ipv6": [ 31 | "2001:DB8::/128" 32 | ] 33 | }, 34 | "description": "An example firewall rule description.", 35 | "label": "firewallrule123", 36 | "ports": "22-24, 80, 443", 37 | "protocol": "TCP" 38 | } 39 | ], 40 | "outbound_policy": "DROP", 41 | "version": 1 42 | } -------------------------------------------------------------------------------- /test/unit/fixtures/image_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "capabilities": [ 3 | "cloud-init", 4 | "distributed-sites" 5 | ], 6 | "created": "2021-08-14T22:44:02", 7 | "created_by": "linode", 8 | "deprecated": false, 9 | "description": "Example image description.", 10 | "eol": "2026-07-01T04:00:00", 11 | "expiry": null, 12 | "id": "linode/debian11", 13 | "is_public": true, 14 | "label": "Debian 11", 15 | "regions": [ 16 | { 17 | "region": "us-iad", 18 | "status": "available" 19 | } 20 | ], 21 | "size": 2500, 22 | "status": "available", 23 | "tags": [ 24 | "repair-image", 25 | "fix-1" 26 | ], 27 | "total_size": 1234567, 28 | "type": "manual", 29 | "updated": "2021-08-14T22:44:02", 30 | "vendor": "Debian" 31 | } -------------------------------------------------------------------------------- /test/unit/fixtures/image_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "capabilities": [ 3 | "cloud-init", 4 | "distributed-sites" 5 | ], 6 | "created": "2021-08-14T22:44:02", 7 | "created_by": "linode", 8 | "deprecated": false, 9 | "description": "Example image description.", 10 | "eol": "2026-07-01T04:00:00", 11 | "expiry": null, 12 | "id": "linode/debian11", 13 | "is_public": true, 14 | "label": "Debian 11", 15 | "regions": [ 16 | { 17 | "region": "us-iad", 18 | "status": "available" 19 | } 20 | ], 21 | "size": 2500, 22 | "status": "available", 23 | "tags": [ 24 | "repair-image", 25 | "fix-1" 26 | ], 27 | "total_size": 1234567, 28 | "type": "manual", 29 | "updated": "2021-08-14T22:44:02", 30 | "vendor": "Debian" 31 | } -------------------------------------------------------------------------------- /test/unit/fixtures/image_replicate.json: -------------------------------------------------------------------------------- 1 | { 2 | "capabilities": [ 3 | "cloud-init", 4 | "distributed-sites" 5 | ], 6 | "created": "2021-08-14T22:44:02", 7 | "created_by": "linode", 8 | "deprecated": false, 9 | "description": "Example image description.", 10 | "eol": "2026-07-01T04:00:00", 11 | "expiry": null, 12 | "id": "linode/debian11", 13 | "is_public": true, 14 | "label": "Debian 11", 15 | "regions": [ 16 | { 17 | "region": "us-iad", 18 | "status": "available" 19 | } 20 | ], 21 | "size": 2500, 22 | "status": "available", 23 | "tags": [ 24 | "repair-image", 25 | "fix-1" 26 | ], 27 | "total_size": 1234567, 28 | "type": "manual", 29 | "updated": "2021-08-14T22:44:02", 30 | "vendor": "Debian" 31 | } -------------------------------------------------------------------------------- /test/unit/fixtures/image_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "capabilities": [ 3 | "cloud-init", 4 | "distributed-sites" 5 | ], 6 | "created": "2021-08-14T22:44:02", 7 | "created_by": "linode", 8 | "deprecated": false, 9 | "description": "Example image description.", 10 | "eol": "2026-07-01T04:00:00", 11 | "expiry": null, 12 | "id": "linode/debian11", 13 | "is_public": true, 14 | "label": "Debian 11", 15 | "regions": [ 16 | { 17 | "region": "us-iad", 18 | "status": "available" 19 | } 20 | ], 21 | "size": 2500, 22 | "status": "available", 23 | "tags": [ 24 | "repair-image", 25 | "fix-1" 26 | ], 27 | "total_size": 1234567, 28 | "type": "manual", 29 | "updated": "2021-08-14T22:44:02", 30 | "vendor": "Debian" 31 | } -------------------------------------------------------------------------------- /test/unit/fixtures/image_upload.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": { 3 | "capabilities": [ 4 | "cloud-init", 5 | "distributed-sites" 6 | ], 7 | "created": "2021-08-14T22:44:02", 8 | "created_by": "linode", 9 | "deprecated": false, 10 | "description": "Example image description.", 11 | "eol": "2026-07-01T04:00:00", 12 | "expiry": null, 13 | "id": "linode/debian11", 14 | "is_public": true, 15 | "label": "Debian 11", 16 | "regions": [ 17 | { 18 | "region": "us-iad", 19 | "status": "available" 20 | } 21 | ], 22 | "size": 2500, 23 | "status": "available", 24 | "tags": [ 25 | "repair-image", 26 | "fix-1" 27 | ], 28 | "total_size": 1234567, 29 | "type": "manual", 30 | "updated": "2021-08-14T22:44:02", 31 | "vendor": "Debian" 32 | }, 33 | "upload_to": "https://example.com/upload-endpoint" 34 | } -------------------------------------------------------------------------------- /test/unit/fixtures/images_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "capabilities": [ 5 | "cloud-init", 6 | "distributed-sites" 7 | ], 8 | "created": "2021-08-14T22:44:02", 9 | "created_by": "linode", 10 | "deprecated": false, 11 | "description": "Example image description.", 12 | "eol": "2026-07-01T04:00:00", 13 | "expiry": null, 14 | "id": "linode/debian11", 15 | "is_public": true, 16 | "label": "Debian 11", 17 | "regions": [ 18 | { 19 | "region": "us-iad", 20 | "status": "available" 21 | } 22 | ], 23 | "size": 2500, 24 | "status": "available", 25 | "tags": [ 26 | "repair-image", 27 | "fix-1" 28 | ], 29 | "total_size": 1234567, 30 | "type": "manual", 31 | "updated": "2021-08-14T22:44:02", 32 | "vendor": "Debian" 33 | } 34 | ], 35 | "page": 1, 36 | "pages": 1, 37 | "results": 1 38 | } -------------------------------------------------------------------------------- /test/unit/fixtures/instance_backups_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "automatic": [ 3 | { 4 | "id": 3, 5 | "label": "auto-backup-1", 6 | "status": "successful", 7 | "created": "2025-02-05T08:00:00", 8 | "available": true 9 | }, 10 | { 11 | "id": 4, 12 | "label": "auto-backup-2", 13 | "status": "successful", 14 | "created": "2025-02-06T08:00:00", 15 | "available": true 16 | } 17 | ], 18 | "snapshot": { 19 | "current": { 20 | "id": 5, 21 | "label": "snapshot-current", 22 | "status": "running", 23 | "available": false 24 | }, 25 | "in_progress": null 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_clone.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 126, 3 | "label": "cloned-instance", 4 | "region": "us-east", 5 | "type": "g6-standard-1", 6 | "status": "provisioning" 7 | } 8 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 3, 3 | "label": "new-config", 4 | "kernel": "linode/latest-64bit", 5 | "root_device": "/dev/sda" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "label": "config-1", 4 | "kernel": "linode/latest-64bit", 5 | "root_device": "/dev/sda" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_interface_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "ipam_address": "192.168.1.2", 4 | "label": "eth0", 5 | "purpose": "vpc", 6 | "primary": true, 7 | "active": true, 8 | "vpc_id": 100, 9 | "subnet_id": 123, 10 | "ipv4": { 11 | "vpc": "10.0.0.1", 12 | "nat_1_1": "192.168.1.1" 13 | }, 14 | "ip_ranges": ["192.168.1.0/24"] 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_interface_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "ipam_address": "192.168.1.10", 4 | "label": "eth0", 5 | "purpose": "public", 6 | "primary": true, 7 | "active": true, 8 | "vpc_id": 101, 9 | "subnet_id": 202, 10 | "ipv4": { 11 | "vpc": "vpc-1", 12 | "nat_1_1": "203.0.113.1" 13 | }, 14 | "ip_ranges": ["192.168.1.0/24"] 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_interface_list.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "ipam_address": "192.168.1.2", 5 | "label": "eth0", 6 | "purpose": "vpc", 7 | "primary": true, 8 | "active": true, 9 | "vpc_id": 100, 10 | "subnet_id": 123, 11 | "ipv4": { 12 | "vpc": "10.0.0.1", 13 | "nat_1_1": "192.168.1.1" 14 | }, 15 | "ip_ranges": ["192.168.1.0/24"] 16 | }, 17 | { 18 | "id": 2, 19 | "ipam_address": "192.168.1.3", 20 | "label": "eth1", 21 | "purpose": "public", 22 | "primary": false, 23 | "active": true 24 | } 25 | ] 26 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_interface_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "ipam_address": "192.168.1.10", 4 | "label": "eth0", 5 | "purpose": "public", 6 | "primary": true, 7 | "active": true, 8 | "vpc_id": 101, 9 | "subnet_id": 202, 10 | "ipv4": { 11 | "vpc": "vpc-2", 12 | "nat_1_1": "203.0.113.3" 13 | }, 14 | "ip_ranges": ["192.168.1.0/24"] 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 1, 5 | "label": "config-1", 6 | "kernel": "linode/latest-64bit", 7 | "root_device": "/dev/sda" 8 | }, 9 | { 10 | "id": 2, 11 | "label": "config-2", 12 | "kernel": "linode/latest-64bit", 13 | "root_device": "/dev/sdb" 14 | } 15 | ], 16 | "page": 1, 17 | "pages": 1, 18 | "results": 2 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_config_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "label": "updated-config", 4 | "kernel": "linode/latest-64bit", 5 | "root_device": "/dev/sdb" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 125, 3 | "label": "new-instance", 4 | "region": "us-east", 5 | "type": "g6-standard-1", 6 | "status": "provisioning" 7 | } 8 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_disk_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 3, 3 | "label": "New Disk", 4 | "status": "ready", 5 | "size": 20480, 6 | "filesystem": "ext4", 7 | "created": "2024-02-01T12:00:00", 8 | "updated": "2024-02-01T12:00:00" 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_disk_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "label": "Disk 1", 4 | "status": "ready", 5 | "size": 20480, 6 | "filesystem": "ext4", 7 | "created": "2024-01-01T12:00:00", 8 | "updated": "2024-01-02T12:00:00" 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_disk_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 1, 5 | "label": "Disk 1", 6 | "status": "ready", 7 | "size": 20480, 8 | "filesystem": "ext4", 9 | "created": "2024-01-01T12:00:00", 10 | "updated": "2024-01-02T12:00:00" 11 | }, 12 | { 13 | "id": 2, 14 | "label": "Disk 2", 15 | "status": "not ready", 16 | "size": 10240, 17 | "filesystem": "swap", 18 | "created": "2024-01-03T12:00:00", 19 | "updated": "2024-01-04T12:00:00" 20 | } 21 | ], 22 | "page": 1, 23 | "pages": 1, 24 | "results": 2 25 | } 26 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_disk_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "label": "Updated Disk", 4 | "status": "ready", 5 | "size": 20480, 6 | "filesystem": "ext4", 7 | "created": "2024-01-01T12:00:00", 8 | "updated": "2024-02-10T12:00:00" 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_disks_clone.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "filesystem": "ext4", 4 | "id": 123, 5 | "label": "Debian 9 Disk", 6 | "size": 48640, 7 | "status": "ready", 8 | "updated": "2018-01-01T00:01:01" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/instance_firewall_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 456, 5 | "label": "firewall-1", 6 | "status": "enabled", 7 | "rules": { 8 | "inbound": [], 9 | "outbound": [] 10 | } 11 | }, 12 | { 13 | "id": 789, 14 | "label": "firewall-2", 15 | "status": "disabled", 16 | "rules": { 17 | "inbound": [], 18 | "outbound": [] 19 | } 20 | } 21 | ], 22 | "page": 1, 23 | "pages": 1, 24 | "results": 2 25 | } 26 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "linode123", 4 | "status": "running", 5 | "region": "us-east", 6 | "type": "g6-standard-1", 7 | "ipv4": ["203.0.113.1"], 8 | "specs": { 9 | "memory": 4096, 10 | "cpus": 2, 11 | "disk": 80000, 12 | "transfer": 2000 13 | }, 14 | "backups": { 15 | "last_successful": "2018-01-01T00:01:01" 16 | }, 17 | "placement_group": { 18 | "migrating_to": 2468 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_ip_add.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "198.51.100.1", 3 | "gateway": "198.51.100.254", 4 | "subnet_mask": "255.255.255.0", 5 | "prefix": 24, 6 | "type": "ipv4", 7 | "public": true, 8 | "linode_id": 123, 9 | "region": "us-west" 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_ip_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "192.0.2.1", 3 | "gateway": "192.0.2.254", 4 | "subnet_mask": "255.255.255.0", 5 | "prefix": 24, 6 | "type": "ipv4", 7 | "public": true, 8 | "rdns": "example.com", 9 | "linode_id": 123, 10 | "region": "us-east" 11 | } 12 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_ip_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "ipv4": { 3 | "public": [ 4 | { 5 | "address": "192.0.2.1", 6 | "gateway": "192.0.2.254", 7 | "subnet_mask": "255.255.255.0", 8 | "prefix": 24, 9 | "type": "ipv4", 10 | "public": true, 11 | "rdns": "example.com", 12 | "linode_id": 123, 13 | "region": "us-east" 14 | } 15 | ], 16 | "private": [], 17 | "shared": [], 18 | "reserved": [], 19 | "vpc": [] 20 | }, 21 | "ipv6": { 22 | "link_local": { 23 | "address": "fe80::1", 24 | "gateway": "fe80::ff", 25 | "prefix": 64 26 | }, 27 | "slaac": { 28 | "address": "2001:db8::1", 29 | "gateway": "2001:db8::ff", 30 | "prefix": 64 31 | }, 32 | "global": [] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_ip_reserved.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "203.0.113.1", 3 | "gateway": "203.0.113.254", 4 | "subnet_mask": "255.255.255.0", 5 | "prefix": 24, 6 | "type": "ipv4", 7 | "public": false, 8 | "linode_id": 123, 9 | "region": "us-central" 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_ip_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "192.0.2.1", 3 | "gateway": "192.0.2.254", 4 | "subnet_mask": "255.255.255.0", 5 | "prefix": 24, 6 | "type": "ipv4", 7 | "public": true, 8 | "rdns": "custom.reverse.dns", 9 | "linode_id": 123, 10 | "region": "us-east" 11 | } 12 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_monthly_transfer_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "bytes_in": 30471077120, 3 | "bytes_out": 22956600198, 4 | "bytes_total": 53427677318 5 | } -------------------------------------------------------------------------------- /test/unit/fixtures/instance_nodebalancers_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "client_conn_throttle": 0, 5 | "created": "2018-01-01T00:01:01", 6 | "hostname": "192.0.2.1.ip.linodeusercontent.com", 7 | "id": 12345, 8 | "ipv4": "203.0.113.1", 9 | "ipv6": null, 10 | "label": "balancer12345", 11 | "region": "us-east", 12 | "tags": [ 13 | "example tag", 14 | "another example" 15 | ], 16 | "transfer": { 17 | "in": 28.91200828552246, 18 | "out": 3.5487728118896484, 19 | "total": 32.46078109741211 20 | }, 21 | "updated": "2018-03-01T00:01:01" 22 | } 23 | ], 24 | "page": 1, 25 | "pages": 1, 26 | "results": 1 27 | } -------------------------------------------------------------------------------- /test/unit/fixtures/instance_rebuild.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "image": "linode/ubuntu22.04" 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_snapshot_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2, 3 | "label": "new-snapshot", 4 | "status": "pending", 5 | "type": "manual", 6 | "created": "2025-02-10T15:00:00", 7 | "configs": ["config-1"], 8 | "disks": [ 9 | { 10 | "label": "disk-1", 11 | "size": 5120, 12 | "filesystem": "ext4" 13 | } 14 | ], 15 | "available": false 16 | } 17 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_snapshot_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "label": "snapshot-1", 4 | "status": "successful", 5 | "type": "manual", 6 | "created": "2025-02-01T10:00:00", 7 | "updated": "2025-02-02T12:00:00", 8 | "finished": "2025-02-02T12:30:00", 9 | "configs": ["config-1", "config-2"], 10 | "disks": [ 11 | { 12 | "label": "disk-1", 13 | "size": 10240, 14 | "filesystem": "ext4" 15 | } 16 | ], 17 | "available": true 18 | } 19 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_stats_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "linode.com - my-linode (linode123456) - day (5 min avg)", 3 | "data": { 4 | "cpu": [ 5 | [1521483600000, 0.42] 6 | ], 7 | "io": { 8 | "io": [ 9 | [1521484800000, 0.19] 10 | ], 11 | "swap": [ 12 | [1521484800000, 0] 13 | ] 14 | }, 15 | "netv4": { 16 | "in": [ 17 | [1521484800000, 2004.36] 18 | ], 19 | "out": [ 20 | [1521484800000, 3928.91] 21 | ], 22 | "private_in": [ 23 | [1521484800000, 0] 24 | ], 25 | "private_out": [ 26 | [1521484800000, 5.6] 27 | ] 28 | }, 29 | "netv6": { 30 | "in": [ 31 | [1521484800000, 0] 32 | ], 33 | "out": [ 34 | [1521484800000, 0] 35 | ], 36 | "private_in": [ 37 | [1521484800000, 195.18] 38 | ], 39 | "private_out": [ 40 | [1521484800000, 5.6] 41 | ] 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "updated-instance" 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/instance_volume_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 1001, 5 | "label": "volume-1", 6 | "size": 50, 7 | "status": "available" 8 | }, 9 | { 10 | "id": 1002, 11 | "label": "volume-2", 12 | "size": 100, 13 | "status": "resizing" 14 | } 15 | ], 16 | "page": 1, 17 | "pages": 1, 18 | "results": 2 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/linode_type_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "g6-standard-2", 3 | "disk": 4000, 4 | "class": "standard", 5 | "price": { 6 | "hourly": 0.015, 7 | "monthly": 10 8 | }, 9 | "label": "Linode 2GB", 10 | "addons": { 11 | "backups": { 12 | "price": { 13 | "hourly": 0.003, 14 | "monthly": 2 15 | }, 16 | "region_prices": [] 17 | } 18 | }, 19 | "region_prices": [], 20 | "network_out": 2000, 21 | "memory": 4000, 22 | "transfer": 500, 23 | "vcpus": 2, 24 | "gpus": 0, 25 | "successor": null 26 | } 27 | -------------------------------------------------------------------------------- /test/unit/fixtures/linode_types_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "g6-nanode-1", 5 | "disk": 25600, 6 | "class": "nanode", 7 | "price": { 8 | "hourly": 0.0075, 9 | "monthly": 5 10 | }, 11 | "label": "Nanode 1GB", 12 | "addons": null, 13 | "region_prices": [], 14 | "network_out": 1000, 15 | "memory": 1024, 16 | "transfer": 250, 17 | "vcpus": 1, 18 | "gpus": 0, 19 | "successor": null 20 | }, 21 | { 22 | "id": "g6-standard-2", 23 | "disk": 51200, 24 | "class": "standard", 25 | "price": { 26 | "hourly": 0.015, 27 | "monthly": 10 28 | }, 29 | "label": "Linode 2GB", 30 | "addons": null, 31 | "region_prices": [], 32 | "network_out": 2000, 33 | "memory": 2048, 34 | "transfer": 500, 35 | "vcpus": 2, 36 | "gpus": 0, 37 | "successor": null 38 | } 39 | ], 40 | "page": 1, 41 | "pages": 1, 42 | "results": 2 43 | } 44 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_apl.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "test-cluster", 4 | "region": "us-east", 5 | "status": "ready", 6 | "apl_enabled": true, 7 | "created": "2025-01-23T00:00:00", 8 | "updated": "2025-01-23T00:00:00" 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_control_plane_acl_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "acl": { 3 | "enabled": true, 4 | "addresses": { 5 | "ipv4": ["192.168.1.1/32"], 6 | "ipv6": ["2001:db8::/32"] 7 | }, 8 | "revision-id": "rev-abc123" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_control_plane_acl_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "acl": { 3 | "enabled": true, 4 | "addresses": { 5 | "ipv4": ["10.0.0.1/32"], 6 | "ipv6": ["2001:db8::/64"] 7 | }, 8 | "revision-id": "rev-abc124" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 125, 3 | "label": "new-cluster", 4 | "region": "us-west", 5 | "status": "ready" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://dashboard.example.com" 3 | } 4 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "test-cluster", 4 | "region": "us-east", 5 | "status": "ready" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_kubeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "kubeconfig": "base64-encoded-kubeconfig" 3 | } 4 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "test-cluster", 6 | "region": "us-east", 7 | "status": "ready" 8 | }, 9 | { 10 | "id": 124, 11 | "label": "second-cluster", 12 | "region": "us-west", 13 | "status": "not_ready" 14 | } 15 | ], 16 | "pages": 1, 17 | "results": 2 18 | } 19 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_pool_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 3, 3 | "type": "g6-standard-2", 4 | "count": 3 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_pool_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "type": "pool-1", 4 | "count": 3, 5 | "autoscaler": {"enabled": true, "min": 1, "max": 5} 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_pool_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 1, 5 | "type": "pool-1", 6 | "count": 3, 7 | "autoscaler": {"enabled": true, "min": 1, "max": 5} 8 | }, 9 | { 10 | "id": 2, 11 | "type": "pool-2", 12 | "count": 2, 13 | "autoscaler": {"enabled": false} 14 | } 15 | ], 16 | "pages": 1, 17 | "results": 2 18 | } 19 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_pool_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "type": "pool-1", 4 | "count": 5 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_regenerate.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "test-cluster", 4 | "region": "us-east" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_cluster_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "updated-cluster", 4 | "region": "us-east", 5 | "status": "ready" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_e_node_pool_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "type": "g6-standard-2", 4 | "count": 2, 5 | "disks": [ 6 | { 7 | "size": 1000, 8 | "type": "ext4" 9 | }], 10 | "labels": {}, 11 | "taints": [], 12 | "tags": ["testing"], 13 | "disk_encryption": "enabled", 14 | "k8s_version": "v1.31.1+lke1", 15 | "update_strategy": "on_recycle" 16 | } -------------------------------------------------------------------------------- /test/unit/fixtures/lke_e_node_pool_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "type": "g6-standard-2", 4 | "count": 2, 5 | "disks": [ 6 | { 7 | "size": 1000, 8 | "type": "ext4" 9 | }], 10 | "labels": {}, 11 | "taints": [], 12 | "tags": ["testing"], 13 | "disk_encryption": "enabled", 14 | "k8s_version": "v1.31.1+lke1", 15 | "update_strategy": "rolling_update" 16 | } -------------------------------------------------------------------------------- /test/unit/fixtures/lke_node_pool_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 789, 3 | "count": 2, 4 | "type": "g6-standard-2", 5 | "tags": ["tag1"], 6 | "labels": {"env": "dev"}, 7 | "taints": [ 8 | { 9 | "key": "taintKey", 10 | "value": "taintValue", 11 | "effect": "NoSchedule" 12 | } 13 | ], 14 | "autoscaler": { 15 | "enabled": true, 16 | "min": 1, 17 | "max": 5 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_node_pool_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "count": 3, 4 | "type": "g6-standard-2", 5 | "tags": ["tag1", "tag2"], 6 | "labels": {"env": "staging"}, 7 | "autoscaler": { 8 | "enabled": true, 9 | "min": 1, 10 | "max": 5 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_node_pool_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 456, 5 | "count": 3, 6 | "type": "g6-standard-2", 7 | "tags": ["tag1"], 8 | "labels": {"env": "staging"}, 9 | "autoscaler": {"enabled": true, "min": 1, "max": 5} 10 | }, 11 | { 12 | "id": 789, 13 | "count": 2, 14 | "type": "g6-standard-4", 15 | "tags": ["tag2"], 16 | "labels": {"env": "prod"}, 17 | "autoscaler": {"enabled": false, "min": 0, "max": 0} 18 | } 19 | ], 20 | "pages": 1, 21 | "results": 2 22 | } 23 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_node_pool_node_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "12345-abcde", 3 | "instance_id": 123456, 4 | "status": "ready" 5 | } -------------------------------------------------------------------------------- /test/unit/fixtures/lke_node_pool_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "count": 5, 4 | "type": "g6-standard-2", 5 | "tags": ["updated-tag"], 6 | "labels": {"env": "prod"}, 7 | "autoscaler": { 8 | "enabled": true, 9 | "min": 2, 10 | "max": 8 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/unit/fixtures/lke_types_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "g6-standard-1", 5 | "label": "Standard 1GB", 6 | "price": { 7 | "hourly": 0.0075, 8 | "monthly": 5.00 9 | }, 10 | "region_prices": [ 11 | { 12 | "hourly": 0.0074, 13 | "monthly": 4.99 14 | }, 15 | { 16 | "hourly": 0.0076, 17 | "monthly": 5.01 18 | } 19 | ] 20 | }, 21 | { 22 | "id": "g6-standard-2", 23 | "label": "Standard 2GB", 24 | "price": { 25 | "hourly": 0.015, 26 | "monthly": 10.00 27 | }, 28 | "region_prices": [ 29 | { 30 | "hourly": 0.0148, 31 | "monthly": 9.90 32 | }, 33 | { 34 | "hourly": 0.0152, 35 | "monthly": 10.10 36 | } 37 | ] 38 | } 39 | ], 40 | "pages": 1, 41 | "results": 2 42 | } 43 | -------------------------------------------------------------------------------- /test/unit/fixtures/longview_client_single.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "apache_client", 4 | "api_key": "API_KEY_123", 5 | "install_code": "install_code_123", 6 | "apps": { 7 | "apache": {}, 8 | "mysql": {}, 9 | "nginx": {} 10 | }, 11 | "created": "2025-01-23T00:00:00", 12 | "updated": "2025-01-23T00:00:00" 13 | } 14 | -------------------------------------------------------------------------------- /test/unit/fixtures/longview_clients_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "apache_client", 6 | "api_key": "API_KEY_123", 7 | "install_code": "install_code_123", 8 | "apps": { 9 | "apache": {}, 10 | "mysql": {}, 11 | "nginx": {} 12 | }, 13 | "created": "2025-01-23T00:00:00", 14 | "updated": "2025-01-23T00:00:00" 15 | }, 16 | { 17 | "id": 124, 18 | "label": "mysql_client", 19 | "api_key": "API_KEY_124", 20 | "install_code": "install_code_124", 21 | "apps": { 22 | "apache": {}, 23 | "mysql": {}, 24 | "nginx": {} 25 | }, 26 | "created": "2025-01-23T00:00:00", 27 | "updated": "2025-01-23T00:00:00" 28 | } 29 | ], 30 | "pages": 1, 31 | "results": 2 32 | } 33 | -------------------------------------------------------------------------------- /test/unit/fixtures/longview_plan.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "longview-plan-id", 3 | "label": "Longview Plan", 4 | "clients_included": 5, 5 | "price": { 6 | "hourly": 50.00, 7 | "monthly": 500.00 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/longview_subscription_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "longview-1", 3 | "label": "Longview Pro", 4 | "clients_included": 3, 5 | "price": { 6 | "hourly": 0.01, 7 | "monthly": 10.00 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/longview_subscriptions_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "longview-1", 5 | "label": "Longview Pro", 6 | "clients_included": 3, 7 | "price": { 8 | "hourly": 0.01, 9 | "monthly": 10.00 10 | } 11 | }, 12 | { 13 | "id": "longview-2", 14 | "label": "Longview Enterprise", 15 | "clients_included": 10, 16 | "price": { 17 | "hourly": 0.05, 18 | "monthly": 50.00 19 | } 20 | } 21 | ], 22 | "pages": 1, 23 | "results": 2 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/monitor_service_token_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "somemonitorservicetoken" 3 | } -------------------------------------------------------------------------------- /test/unit/fixtures/monitor_services.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "label": "Databases", 5 | "service_type": "dbaas" 6 | } 7 | ], 8 | "page": 1, 9 | "pages": 1, 10 | "results": 1 11 | } -------------------------------------------------------------------------------- /test/unit/fixtures/mysql_database_credentials_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "password": "s3cur3P@ssw0rd", 3 | "username": "linroot" 4 | } -------------------------------------------------------------------------------- /test/unit/fixtures/mysql_database_ssl_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "ca_certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClRoaXMgaXMgYSB0ZXN0IGNlcnRpZmljYXRlCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" 3 | } -------------------------------------------------------------------------------- /test/unit/fixtures/network_ip_address_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "192.168.1.1", 3 | "linode_id": 12345, 4 | "reserved": false 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/fixtures/network_ip_addresses_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "address": "192.168.1.1", 5 | "linode_id": 12345, 6 | "reserved": false 7 | }, 8 | { 9 | "address": "192.168.1.2", 10 | "linode_id": 67890, 11 | "reserved": true 12 | } 13 | ], 14 | "pages": 1, 15 | "results": 2 16 | } 17 | -------------------------------------------------------------------------------- /test/unit/fixtures/network_ipv6_pools_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "range": "2600:3c00::/64", 3 | "region": "us-east", 4 | "prefix": 64, 5 | "route_target": "2600:3c00::1", 6 | "is_bgp": false, 7 | "linodes": [54321] 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/network_ipv6_pools_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "range": "2600:3c00::/64", 5 | "region": "us-east", 6 | "prefix": 64, 7 | "route_target": "2600:3c00::1", 8 | "is_bgp": true, 9 | "linodes": [12345, 67890] 10 | } 11 | ], 12 | "pages": 1, 13 | "page": 1, 14 | "results": 1 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/network_ipv6_ranges_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "range": "2600:3c00::/64", 3 | "region": "us-east", 4 | "prefix": 64, 5 | "route_target": "2600:3c00::1", 6 | "is_bgp": false, 7 | "linodes": [12345] 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/network_ipv6_ranges_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "range": "2600:3c00::/64", 3 | "region": "us-east", 4 | "prefix": 64, 5 | "route_target": "2600:3c00::1", 6 | "is_bgp": false, 7 | "linodes": [54321] 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/network_ipv6_ranges_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "range": "2600:3c00::/64", 5 | "region": "us-east", 6 | "prefix": 64, 7 | "route_target": "2600:3c00::1", 8 | "is_bgp": true, 9 | "linodes": [12345, 67890] 10 | } 11 | ], 12 | "pages": 1, 13 | "results": 1 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/fixtures/network_reserved_ips.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "192.168.1.30", 3 | "region": "us-west", 4 | "linode_id": 13579, 5 | "label": "test-ip-3", 6 | "created": "2025-02-03T12:00:00", 7 | "status": "reserved" 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/fixtures/network_reserved_ips_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "192.168.1.10", 3 | "region": "us-east", 4 | "linode_id": 12345, 5 | "label": "test-ip-1", 6 | "created": "2025-02-03T12:00:00", 7 | "status": "reserved" 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/fixtures/network_reserved_ips_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "address": "192.168.1.10", 5 | "region": "us-east", 6 | "linode_id": 12345, 7 | "label": "test-ip-1", 8 | "created": "2025-02-03T12:00:00", 9 | "status": "reserved" 10 | }, 11 | { 12 | "address": "192.168.1.20", 13 | "region": "us-west", 14 | "linode_id": 67890, 15 | "label": "test-ip-2", 16 | "created": "2025-02-03T12:00:00", 17 | "status": "reserved" 18 | } 19 | ], 20 | "pages": 1, 21 | "results": 2 22 | } 23 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_config_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "port": 80, 4 | "protocol": "http", 5 | "algorithm": "roundrobin", 6 | "stickiness": "table", 7 | "check": "connection", 8 | "check_interval": 5, 9 | "check_attempts": 3, 10 | "check_path": "/", 11 | "check_body": "", 12 | "check_passive": true, 13 | "check_timeout": 30, 14 | "cipher_suite": "recommended", 15 | "nodebalancer_id": 123, 16 | "ssl_commonname": "", 17 | "ssl_fingerprint": "", 18 | "ssl_cert": "", 19 | "ssl_key": "", 20 | "nodes_status": { 21 | "up": 2, 22 | "down": 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_config_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "port": 80, 4 | "protocol": "http", 5 | "algorithm": "roundrobin", 6 | "stickiness": "table", 7 | "check": "connection", 8 | "check_interval": 5, 9 | "check_attempts": 3, 10 | "check_path": "/", 11 | "check_body": "", 12 | "check_passive": true, 13 | "check_timeout": 30, 14 | "cipher_suite": "recommended", 15 | "nodebalancer_id": 123, 16 | "ssl_commonname": "", 17 | "ssl_fingerprint": "", 18 | "ssl_cert": "", 19 | "ssl_key": "", 20 | "nodes_status": { 21 | "up": 2, 22 | "down": 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_config_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 456, 5 | "address": "192.168.1.1", 6 | "label": "Test Node", 7 | "status": "UP", 8 | "weight": 50, 9 | "mode": "accept", 10 | "config_id": 456, 11 | "nodebalancer_id": 123, 12 | "port": 80, 13 | "protocol": "http" 14 | }, 15 | { 16 | "id": 457, 17 | "address": "192.168.1.2", 18 | "label": "Backup Node", 19 | "status": "UP", 20 | "weight": 40, 21 | "mode": "backup", 22 | "config_id": 456, 23 | "nodebalancer_id": 123, 24 | "port": 80, 25 | "protocol": "http" 26 | } 27 | ], 28 | "page": 1, 29 | "pages": 1, 30 | "results": 2 31 | } 32 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_config_rebuild.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "port": 443, 4 | "protocol": "https", 5 | "algorithm": "roundrobin", 6 | "stickiness": "none", 7 | "check": "connection", 8 | "check_interval": 5, 9 | "check_attempts": 3, 10 | "check_path": "/", 11 | "check_body": "", 12 | "check_passive": true, 13 | "check_timeout": 30, 14 | "cipher_suite": "recommended", 15 | "nodebalancer_id": 123, 16 | "ssl_commonname": "", 17 | "ssl_fingerprint": "", 18 | "ssl_cert": "", 19 | "ssl_key": "", 20 | "nodes_status": { 21 | "up": 2, 22 | "down": 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_config_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "port": 443, 4 | "protocol": "https", 5 | "algorithm": "roundrobin", 6 | "stickiness": "none", 7 | "check": "connection", 8 | "check_interval": 5, 9 | "check_attempts": 3, 10 | "check_path": "/", 11 | "check_body": "", 12 | "check_passive": true, 13 | "check_timeout": 30, 14 | "cipher_suite": "recommended", 15 | "nodebalancer_id": 123, 16 | "ssl_commonname": "", 17 | "ssl_fingerprint": "", 18 | "ssl_cert": "", 19 | "ssl_key": "", 20 | "nodes_status": { 21 | "up": 2, 22 | "down": 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Test NodeBalancer", 4 | "region": "us-east", 5 | "hostname": "test.nodebalancer.linode.com", 6 | "ipv4": "192.0.2.1", 7 | "ipv6": "2600:3c03::f03c:91ff:fe24:9dcf", 8 | "client_conn_throttle": 10, 9 | "transfer": { 10 | "total": 1000.5, 11 | "in": 500.3, 12 | "out": 500.2 13 | }, 14 | "tags": ["test", "example"], 15 | "created": "2025-02-01T10:00:00", 16 | "updated": "2025-02-06T10:00:00" 17 | } 18 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_firewall_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 789, 5 | "label": "firewall-1", 6 | "status": "enabled" 7 | }, 8 | { 9 | "id": 790, 10 | "label": "firewall-2", 11 | "status": "disabled" 12 | } 13 | ], 14 | "page": 1, 15 | "pages": 1, 16 | "results": 2 17 | } 18 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Existing NodeBalancer", 4 | "region": "us-west", 5 | "hostname": "existing.nodebalancer.linode.com", 6 | "ipv4": "192.0.2.2", 7 | "ipv6": "2600:3c03::f03c:91ff:fe24:abcd", 8 | "client_conn_throttle": 20, 9 | "transfer": { 10 | "total": 2000.0, 11 | "in": 1000.0, 12 | "out": 1000.0 13 | }, 14 | "tags": ["production"], 15 | "created": "2025-01-15T08:00:00", 16 | "updated": "2025-02-05T12:00:00" 17 | } 18 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_node_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 789, 3 | "address": "192.168.1.1", 4 | "label": "Test Node", 5 | "status": "UP", 6 | "weight": 50, 7 | "mode": "accept", 8 | "config_id": 456, 9 | "nodebalancer_id": 123 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_node_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 789, 5 | "address": "192.168.1.1", 6 | "label": "Test Node", 7 | "status": "UP", 8 | "weight": 50, 9 | "mode": "accept", 10 | "config_id": 456, 11 | "nodebalancer_id": 123 12 | }, 13 | { 14 | "id": 790, 15 | "address": "192.168.1.2", 16 | "label": "Backup Node", 17 | "status": "UP", 18 | "weight": 40, 19 | "mode": "backup", 20 | "config_id": 456, 21 | "nodebalancer_id": 123 22 | } 23 | ], 24 | "page": 1, 25 | "pages": 1, 26 | "results": 2 27 | } 28 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_node_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 789, 3 | "address": "192.168.1.2", 4 | "label": "Updated Node", 5 | "status": "UP", 6 | "weight": 60, 7 | "mode": "drain", 8 | "config_id": 456, 9 | "nodebalancer_id": 123 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_stats_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "NodeBalancer Stats", 3 | "data": { 4 | "connections": [ 5 | [1000.0, 2000.0], 6 | [3000.0, 4000.0] 7 | ], 8 | "traffic": { 9 | "in": [ 10 | [1000.0, 2000.0], 11 | [3000.0, 4000.0] 12 | ], 13 | "out": [ 14 | [500.0, 1000.0], 15 | [1500.0, 2000.0] 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancer_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "label": "Updated NodeBalancer", 4 | "region": "us-west", 5 | "hostname": "updated.nodebalancer.linode.com", 6 | "ipv4": "192.0.2.5", 7 | "ipv6": "2600:3c03::f03c:91ff:fe24:3333", 8 | "client_conn_throttle": 5, 9 | "transfer": { 10 | "total": 1500.0, 11 | "in": 750.0, 12 | "out": 750.0 13 | }, 14 | "tags": ["updated", "production"], 15 | "created": "2025-01-15T08:00:00", 16 | "updated": "2025-02-06T15:00:00" 17 | } 18 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancers_configs_create_udp.json: -------------------------------------------------------------------------------- 1 | { 2 | "algorithm": "ring_hash", 3 | "check": "http_body", 4 | "check_attempts": 3, 5 | "check_body": "it works", 6 | "check_interval": 90, 7 | "check_path": "/test", 8 | "check_timeout": 10, 9 | "cipher_suite": "recommended", 10 | "id": 4567, 11 | "nodebalancer_id": 1234, 12 | "nodes_status": { 13 | "down": 0, 14 | "up": 4 15 | }, 16 | "port": 1234, 17 | "protocol": "udp", 18 | "ssl_commonname": "www.example.com", 19 | "ssl_fingerprint": "00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F:10:11:12:13", 20 | "ssl_key": "", 21 | "stickiness": "source_ip", 22 | "udp_check_port": 12345, 23 | "udp_session_timeout": 10 24 | } -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancers_create_udp.json: -------------------------------------------------------------------------------- 1 | { 2 | "client_conn_throttle": 0, 3 | "client_udp_sess_throttle": 10, 4 | "created": "2018-01-01T00:01:01", 5 | "hostname": "192.0.2.1.ip.linodeusercontent.com", 6 | "id": 12345, 7 | "ipv4": "203.0.113.1", 8 | "ipv6": null, 9 | "label": "balancer12345", 10 | "region": "us-mia", 11 | "tags": [ 12 | "example tag", 13 | "another example" 14 | ], 15 | "transfer": { 16 | "in": 28.91200828552246, 17 | "out": 3.5487728118896484, 18 | "total": 32.46078109741211 19 | }, 20 | "updated": "2018-03-01T00:01:01" 21 | } -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancers_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "NodeBalancer A", 6 | "region": "us-east", 7 | "tags": ["tag1", "tag2"] 8 | }, 9 | { 10 | "id": 456, 11 | "label": "NodeBalancer B", 12 | "region": "us-west", 13 | "tags": ["tag3"] 14 | } 15 | ], 16 | "page": 1, 17 | "pages": 1, 18 | "results": 2 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/nodebalancers_types_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "123", 5 | "label": "NodeBalancer A", 6 | "region": "us-east", 7 | "tags": ["tag1", "tag2"], 8 | "price": { 9 | "hourly": 0.10, 10 | "monthly": 10.00 11 | } 12 | }, 13 | { 14 | "id": "456", 15 | "label": "NodeBalancer B", 16 | "region": "us-west", 17 | "tags": ["tag3"], 18 | "price": { 19 | "hourly": 0.15, 20 | "monthly": 15.00 21 | } 22 | } 23 | ], 24 | "page": 1, 25 | "pages": 1, 26 | "results": 2 27 | } 28 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_bucket_access_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "acl": "public-read", 3 | "cors_enabled": true 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_bucket_cert.json: -------------------------------------------------------------------------------- 1 | { 2 | "ssl": true 3 | } 4 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_bucket_contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "etag": "12345abcde", 5 | "last_modified": "2023-01-01T12:00:00Z", 6 | "name": "example-file.txt", 7 | "owner": "user123", 8 | "size": 1024 9 | } 10 | ], 11 | "is_truncated": true, 12 | "next_marker": "next-file-marker" 13 | } 14 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_bucket_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "new-bucket", 3 | "region": "us-east", 4 | "s3_endpoint": "https://s3.us-east.linodeobjects.com", 5 | "endpoint_type": "public", 6 | "hostname": "new-bucket.us-east.linodeobjects.com", 7 | "objects": 0, 8 | "size": 0 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_bucket_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "my-bucket", 3 | "region": "us-east-1", 4 | "s3_endpoint": "https://s3.us-east-1.linodeobjects.com", 5 | "endpoint_type": "public", 6 | "hostname": "my-bucket.us-east-1.linodeobjects.com", 7 | "objects": 10, 8 | "size": 20480 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_bucket_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "label": "my-bucket", 5 | "region": "us-east-1", 6 | "s3_endpoint": "https://s3.us-east-1.linodeobjects.com", 7 | "endpoint_type": "public", 8 | "hostname": "my-bucket.us-east-1.linodeobjects.com", 9 | "objects": 5, 10 | "size": 10240 11 | } 12 | ], 13 | "page": 1, 14 | "pages": 1, 15 | "results": 1 16 | } 17 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_buckets_object_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "name": "example", 5 | "size": 123, 6 | "last_modified": "2018-01-02T03:04:05.757Z", 7 | "etag": "9f254c71e28e033bf9e0e5262e3e72ab", 8 | "owner": "bfc70ab2-e3d4-42a4-ad55-83921822270c" 9 | } 10 | ], 11 | "next_marker": null, 12 | "is_truncated": false 13 | } -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_cluster_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "my-cluster-id", 3 | "domain": "example.com", 4 | "status": "active", 5 | "region": "us-east-1", 6 | "static_site_domain": "static.example.com" 7 | } 8 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_cluster_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "my-cluster-id", 5 | "domain": "example.com", 6 | "status": "active", 7 | "region": "us-east-1", 8 | "static_site_domain": "static.example.com" 9 | } 10 | ], 11 | "page": 1, 12 | "pages": 1, 13 | "results": 1 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_endpoints_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "region": "us-east-1", 5 | "s3_endpoint": "https://s3.us-east-1.linodeobjects.com", 6 | "endpoint_type": "E0" 7 | }, 8 | { 9 | "region": "us-west-1", 10 | "s3_endpoint": "https://s3.us-west-1.linodeobjects.com", 11 | "endpoint_type": "E1" 12 | } 13 | ], 14 | "page": 1, 15 | "pages": 1, 16 | "results": 2 17 | } 18 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_key_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 124, 3 | "label": "new-key", 4 | "access_key": "new-access-key", 5 | "secret_key": "new-secret-key", 6 | "limited": true, 7 | "bucket_access": [ 8 | { 9 | "region": "us-east-1", 10 | "bucket_name": "my-bucket", 11 | "permissions": "read-write" 12 | } 13 | ], 14 | "regions": [ 15 | { 16 | "id": "us-east-1", 17 | "s3_endpoint": "https://s3.us-east-1.linodeobjects.com", 18 | "endpoint_type": "E0" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_key_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "my-key", 4 | "access_key": "my-access-key", 5 | "secret_key": "my-secret-key", 6 | "limited": true, 7 | "bucket_access": [ 8 | { 9 | "region": "us-east-1", 10 | "bucket_name": "my-bucket", 11 | "permissions": "read-write" 12 | } 13 | ], 14 | "regions": [ 15 | { 16 | "id": "us-east-1", 17 | "s3_endpoint": "https://s3.us-east-1.linodeobjects.com", 18 | "endpoint_type": "E0" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_key_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "my-key", 6 | "access_key": "my-access-key", 7 | "secret_key": "my-secret-key", 8 | "limited": true, 9 | "bucket_access": [ 10 | { 11 | "region": "us-east-1", 12 | "bucket_name": "my-bucket", 13 | "permissions": "read-write" 14 | } 15 | ], 16 | "regions": [ 17 | { 18 | "id": "us-east-1", 19 | "s3_endpoint": "https://s3.us-east-1.linodeobjects.com", 20 | "endpoint_type": "E0" 21 | } 22 | ] 23 | } 24 | ], 25 | "page": 1, 26 | "pages": 1, 27 | "results": 1 28 | } 29 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_key_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "updated-key", 4 | "access_key": "updated-access-key", 5 | "secret_key": "updated-secret-key", 6 | "limited": true, 7 | "bucket_access": [ 8 | { 9 | "region": "us-west-1", 10 | "bucket_name": "updated-bucket", 11 | "permissions": "read-only" 12 | } 13 | ], 14 | "regions": [ 15 | { 16 | "id": "us-west-1", 17 | "s3_endpoint": "https://s3.us-west-1.linodeobjects.com", 18 | "endpoint_type": "E1" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_object_acl_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "acl": "public-read", 3 | "acl_xml": "owner-idREAD" 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_object_acl_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "acl": "private", 3 | "acl_xml": "owner-idNONE" 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_object_url_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://s3.example.com/my-bucket/test-object", 3 | "exists": true 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_quotas_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "quota_id": "obj-objects-us-ord-1", 3 | "quota_name": "Object Storage Maximum Objects", 4 | "description": "Maximum number of Objects this customer is allowed to have on this endpoint.", 5 | "endpoint_type": "E1", 6 | "s3_endpoint": "us-iad-1.linodeobjects.com", 7 | "quota_limit": 50, 8 | "resource_metric": "object" 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_quotas_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data":[ 3 | { 4 | "quota_id": "obj-objects-us-ord-1", 5 | "quota_name": "Object Storage Maximum Objects", 6 | "description": "Maximum number of Objects this customer is allowed to have on this endpoint.", 7 | "endpoint_type": "E1", 8 | "s3_endpoint": "us-iad-1.linodeobjects.com", 9 | "quota_limit": 50, 10 | "resource_metric": "object" 11 | }, 12 | { 13 | "quota_id": "obj-bucket-us-ord-1", 14 | "quota_name": "Object Storage Maximum Buckets", 15 | "description": "Maximum number of buckets this customer is allowed to have on this endpoint.", 16 | "endpoint_type": "E1", 17 | "s3_endpoint": "us-iad-1.linodeobjects.com", 18 | "quota_limit": 50, 19 | "resource_metric": "bucket" 20 | }], 21 | "page": 1, 22 | "pages": 1, 23 | "results": 2 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/object_storage_quotas_usage_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "quota_limit": 100, 3 | "usage": 10 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/placement_group_assign.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 528, 3 | "is_compliant": true, 4 | "label": "PG_Miami_failover", 5 | "members": [ 6 | { 7 | "is_compliant": true, 8 | "linode_id": 123 9 | }, 10 | { 11 | "is_compliant": true, 12 | "linode_id": 456 13 | } 14 | ], 15 | "placement_group_policy": "strict", 16 | "placement_group_type": "anti-affinity:local", 17 | "region": "us-mia" 18 | } -------------------------------------------------------------------------------- /test/unit/fixtures/placement_group_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 528, 3 | "is_compliant": true, 4 | "label": "PG_Miami_failover", 5 | "members": [ 6 | { 7 | "is_compliant": true, 8 | "linode_id": 123 9 | } 10 | ], 11 | "placement_group_policy": "strict", 12 | "placement_group_type": "anti-affinity:local", 13 | "region": "us-mia" 14 | } -------------------------------------------------------------------------------- /test/unit/fixtures/placement_group_unassign.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 528, 3 | "is_compliant": true, 4 | "label": "PG_Miami_failover", 5 | "members": [ 6 | { 7 | "is_compliant": true, 8 | "linode_id": 123 9 | } 10 | ], 11 | "placement_group_policy": "strict", 12 | "placement_group_type": "anti-affinity:local", 13 | "region": "us-mia" 14 | } -------------------------------------------------------------------------------- /test/unit/fixtures/placement_group_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 528, 3 | "is_compliant": true, 4 | "label": "PG_Miami_failover_new", 5 | "members": [ 6 | { 7 | "is_compliant": true, 8 | "linode_id": 123 9 | } 10 | ], 11 | "placement_group_policy": "strict", 12 | "placement_group_type": "anti-affinity:local", 13 | "region": "us-mia" 14 | } -------------------------------------------------------------------------------- /test/unit/fixtures/placement_groups_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 528, 3 | "is_compliant": true, 4 | "label": "PG_Miami_failover", 5 | "members": [ 6 | { 7 | "is_compliant": true, 8 | "linode_id": 123 9 | } 10 | ], 11 | "migrations": { 12 | "inbound": [ 13 | { 14 | "linode_id": 123 15 | } 16 | ], 17 | "outbound": [ 18 | { 19 | "linode_id": 456 20 | } 21 | ] 22 | }, 23 | "placement_group_policy": "strict", 24 | "placement_group_type": "anti-affinity:local", 25 | "region": "us-mia" 26 | } -------------------------------------------------------------------------------- /test/unit/fixtures/placement_groups_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 528, 5 | "is_compliant": true, 6 | "label": "PG_Miami_failover", 7 | "members": [ 8 | { 9 | "is_compliant": true, 10 | "linode_id": 123 11 | } 12 | ], 13 | "migrations": { 14 | "inbound": [ 15 | { 16 | "linode_id": 123 17 | } 18 | ], 19 | "outbound": [ 20 | { 21 | "linode_id": 456 22 | } 23 | ] 24 | }, 25 | "placement_group_policy": "strict", 26 | "placement_group_type": "anti-affinity:local", 27 | "region": "us-mia" 28 | } 29 | ], 30 | "page": 1, 31 | "pages": 1, 32 | "results": 1 33 | } -------------------------------------------------------------------------------- /test/unit/fixtures/postgresql_database_credentials_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "password": "s3cur3P@ssw0rd", 3 | "username": "linroot" 4 | } -------------------------------------------------------------------------------- /test/unit/fixtures/postgresql_database_ssl_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "ca_certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClRoaXMgaXMgYSB0ZXN0IGNlcnRpZmljYXRlCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" 3 | } -------------------------------------------------------------------------------- /test/unit/fixtures/postgresql_databases_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "allow_list": [ 5 | "203.0.113.1/32", 6 | "192.0.1.0/24" 7 | ], 8 | "cluster_size": 3, 9 | "created": "2022-01-01T00:01:01", 10 | "encrypted": true, 11 | "engine": "postgresql", 12 | "fork": { 13 | "restore_time": "2024-10-14T19:55:12", 14 | "source": 176881 15 | }, 16 | "hosts": { 17 | "primary": "lin-0000-000-pgsql-primary.servers.linodedb.net", 18 | "secondary": "lin-0000-000-pgsql-primary-private.servers.linodedb.net" 19 | }, 20 | "id": 123, 21 | "label": "example-db", 22 | "members": { 23 | "45.56.110.70": "primary", 24 | "45.79.159.239": "failover" 25 | }, 26 | "platform": "rdbms-default", 27 | "port": 3306, 28 | "region": "us-east", 29 | "ssl_connection": true, 30 | "status": "active", 31 | "total_disk_size_gb": 15, 32 | "type": "g6-dedicated-2", 33 | "updated": "2022-01-01T00:01:01", 34 | "updates": { 35 | "day_of_week": 1, 36 | "duration": 3, 37 | "frequency": "weekly", 38 | "hour_of_day": 0, 39 | "pending": [] 40 | }, 41 | "used_disk_size_gb": 2, 42 | "version": "13.2" 43 | } 44 | ], 45 | "page": 1, 46 | "pages": 1, 47 | "results": 1 48 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_apps_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T00:01:01", 3 | "expiry": "2018-01-15T00:01:01", 4 | "id": 123, 5 | "label": "example-app", 6 | "scopes": "linodes:read_only", 7 | "thumbnail_url": null, 8 | "website": "example.org" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_apps_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created": "2018-01-01T00:01:01", 5 | "expiry": "2018-01-15T00:01:01", 6 | "id": 123, 7 | "label": "example-app", 8 | "scopes": "linodes:read_only", 9 | "thumbnail_url": null, 10 | "website": "example.org" 11 | } 12 | ], 13 | "page": 1, 14 | "pages": 1, 15 | "results": 1 16 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_devices_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "created": "2018-01-01T01:01:01", 3 | "expiry": "2018-01-31T01:01:01", 4 | "id": 123, 5 | "last_authenticated": "2018-01-05T12:57:12", 6 | "last_remote_addr": "203.0.113.1", 7 | "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36" 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_devices_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created": "2018-01-01T01:01:01", 5 | "expiry": "2018-01-31T01:01:01", 6 | "id": 123, 7 | "last_authenticated": "2018-01-05T12:57:12", 8 | "last_remote_addr": "203.0.113.1", 9 | "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36" 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 1 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "authentication_type": "password", 3 | "authorized_keys": null, 4 | "email": "example-user@gmail.com", 5 | "email_notifications": true, 6 | "lish_auth_method": "keys_only", 7 | "referrals": { 8 | "code": "871be32f49c1411b14f29f618aaf0c14637fb8d3", 9 | "completed": 0, 10 | "credit": 0, 11 | "pending": 0, 12 | "total": 0, 13 | "url": "https://www.linode.com/?r=871be32f49c1411b14f29f618aaf0c14637fb8d3" 14 | }, 15 | "restricted": false, 16 | "timezone": "US/Eastern", 17 | "two_factor_auth": true, 18 | "uid": 1234, 19 | "username": "exampleUser", 20 | "verified_phone_number": "+5555555555" 21 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_login_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "ip": "192.0.2.10", 4 | "restricted": false, 5 | "status": "successful", 6 | "username": "testuser", 7 | "datetime": "2024-01-15T14:30:00" 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_logins_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "ip": "203.0.113.5", 6 | "restricted": true, 7 | "status": "failed", 8 | "username": "user1", 9 | "datetime": "2024-02-01T10:15:30" 10 | }, 11 | { 12 | "id": 124, 13 | "ip": "198.51.100.25", 14 | "restricted": false, 15 | "status": "successful", 16 | "username": "user2", 17 | "datetime": "2024-02-02T18:45:00" 18 | } 19 | ], 20 | "page": 1, 21 | "pages": 1, 22 | "results": 2 23 | } 24 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_preferences_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": "value1", 3 | "key2": "value2" 4 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_preferences_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": "value1_new", 3 | "key2": "value2_new" 4 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_security_question_answer.json: -------------------------------------------------------------------------------- 1 | { 2 | "security_questions": [ 3 | { 4 | "question_id": 1, 5 | "response": "Gotham City", 6 | "security_question": "In what city were you born?" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_security_question_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "security_questions": [ 3 | { 4 | "id": 1, 5 | "question": "In what city were you born?", 6 | "response": "Gotham City" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_sshkey_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 125, 3 | "label": "Test Key", 4 | "ssh_key": "ssh-rsa AAAAB3...", 5 | "created": "2024-03-12T08:30:00" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_sshkey_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "My SSH Key", 4 | "ssh_key": "ssh-rsa AAAAB3...", 5 | "created": "2024-03-10T12:00:00" 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_sshkey_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Updated Key", 4 | "ssh_key": "ssh-rsa AAAAB3...", 5 | "created": "2024-03-10T12:00:00" 6 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_sshkeys_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "My SSH Key", 6 | "ssh_key": "ssh-rsa AAAAB3...", 7 | "created": "2024-03-10T12:00:00" 8 | }, 9 | { 10 | "id": 124, 11 | "label": "Another SSH Key", 12 | "ssh_key": "ssh-rsa AAAAB3...", 13 | "created": "2024-03-11T15:45:00" 14 | } 15 | ], 16 | "pages": 1, 17 | "results": 2 18 | } 19 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_token_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 125, 3 | "label": "New API Token", 4 | "scopes": "read_write", 5 | "token": "newtoken123", 6 | "created": "2025-01-01T08:00:00", 7 | "expiry": "2025-06-01T08:00:00" 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_token_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "My API Token", 4 | "scopes": "read_write", 5 | "token": "abcd1234", 6 | "created": "2024-03-10T12:00:00", 7 | "expiry": "2024-09-10T12:00:00" 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_token_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Updated API Token", 4 | "scopes": "read_write", 5 | "token": "abcd1234", 6 | "created": "2024-03-10T12:00:00", 7 | "expiry": "2024-09-10T12:00:00" 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_tokens_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "My API Token", 6 | "scopes": "read_write", 7 | "token": "abcd1234", 8 | "created": "2024-03-10T12:00:00", 9 | "expiry": "2024-09-10T12:00:00" 10 | }, 11 | { 12 | "id": 124, 13 | "label": "Another API Token", 14 | "scopes": "read_only", 15 | "token": "xyz9876", 16 | "created": "2024-03-11T15:45:00", 17 | "expiry": "2024-10-11T15:45:00" 18 | } 19 | ], 20 | "pages": 1, 21 | "results": 2 22 | } 23 | -------------------------------------------------------------------------------- /test/unit/fixtures/profile_two_factor_enable.json: -------------------------------------------------------------------------------- 1 | { 2 | "scratch": "reallycoolandlegittfacode" 3 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_two_factor_secret_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "expiry": "2018-03-01T00:01:01", 3 | "secret": "5FXX6KLACOC33GTC" 4 | } -------------------------------------------------------------------------------- /test/unit/fixtures/profile_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "authentication_type": "password", 3 | "authorized_keys": null, 4 | "email": "example-user-new@gmail.com", 5 | "email_notifications": true, 6 | "lish_auth_method": "keys_only", 7 | "referrals": { 8 | "code": "871be32f49c1411b14f29f618aaf0c14637fb8d3", 9 | "completed": 0, 10 | "credit": 0, 11 | "pending": 0, 12 | "total": 0, 13 | "url": "https://www.linode.com/?r=871be32f49c1411b14f29f618aaf0c14637fb8d3" 14 | }, 15 | "restricted": false, 16 | "timezone": "US/Eastern", 17 | "two_factor_auth": true, 18 | "uid": 1234, 19 | "username": "exampleUser", 20 | "verified_phone_number": "+5555555555" 21 | } -------------------------------------------------------------------------------- /test/unit/fixtures/region_availability_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "region": "us-east", 3 | "available": true, 4 | "plan": "Linode 2GB" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/fixtures/region_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "us-east", 3 | "country": "US", 4 | "capabilities": ["Linodes", "Block Storage", "Object Storage"], 5 | "status": "ok", 6 | "label": "Newark, NJ", 7 | "site_type": "standard", 8 | "resolvers": { 9 | "ipv4": "8.8.8.8", 10 | "ipv6": "2001:4860:4860::8888" 11 | }, 12 | "placement_group_limits": { 13 | "maximum_pgs_per_customer": 5, 14 | "maximum_linodes_per_pg": 10 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/unit/fixtures/regions_availability_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "region": "us-east", 5 | "available": true, 6 | "plan": "Linode 2GB" 7 | } 8 | ], 9 | "page": 1, 10 | "pages": 1, 11 | "results": 1 12 | } 13 | -------------------------------------------------------------------------------- /test/unit/fixtures/regions_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "us-east", 5 | "country": "US", 6 | "capabilities": ["Linodes", "Block Storage", "Object Storage"], 7 | "status": "ok", 8 | "label": "US East", 9 | "site_type": "standard", 10 | "resolvers": { 11 | "ipv4": "8.8.8.8", 12 | "ipv6": "2001:4860:4860::8888" 13 | }, 14 | "placement_group_limits": { 15 | "maximum_pgs_per_customer": 10, 16 | "maximum_linodes_per_pg": 5 17 | } 18 | } 19 | ], 20 | "page": 1, 21 | "pages": 1, 22 | "results": 1 23 | } 24 | 25 | -------------------------------------------------------------------------------- /test/unit/fixtures/stackscript_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "username": "testuser", 4 | "label": "new-stackscript", 5 | "description": "Test Description", 6 | "ordinal": 1, 7 | "logo_url": "https://example.com/logo.png", 8 | "images": ["linode/ubuntu20.04"], 9 | "deployments_total": 10, 10 | "deployments_active": 5, 11 | "is_public": true, 12 | "mine": true, 13 | "rev_note": "Initial revision", 14 | "script": "#!/bin/bash\necho Hello", 15 | "user_defined_fields": [], 16 | "user_gravatar_id": "abcdef123456" 17 | } 18 | -------------------------------------------------------------------------------- /test/unit/fixtures/stackscript_revision.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Updated Stackscript", 4 | "rev_note": "Updated revision" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/fixtures/stackscripts_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "username": "testuser", 6 | "label": "Test Stackscript", 7 | "description": "A test Stackscript", 8 | "images": ["linode/ubuntu20.04"], 9 | "deployments_total": 10, 10 | "deployments_active": 5, 11 | "is_public": true, 12 | "mine": true, 13 | "rev_note": "Initial version", 14 | "script": "#!/bin/bash\necho Hello", 15 | "user_defined_fields": [], 16 | "user_gravatar_id": "abc123" 17 | }, 18 | { 19 | "id": 456, 20 | "username": "anotheruser", 21 | "label": "Another Stackscript", 22 | "description": "Another test Stackscript", 23 | "images": ["linode/debian10"], 24 | "deployments_total": 3, 25 | "deployments_active": 1, 26 | "is_public": false, 27 | "mine": false, 28 | "rev_note": "Another version", 29 | "script": "#!/bin/bash\necho Another", 30 | "user_defined_fields": [], 31 | "user_gravatar_id": "xyz456" 32 | } 33 | ], 34 | "page": 1, 35 | "pages": 1, 36 | "results": 2 37 | } 38 | -------------------------------------------------------------------------------- /test/unit/fixtures/support_ticket_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachments": [ 3 | "screenshot.jpg", 4 | "screenshot.txt" 5 | ], 6 | "closable": false, 7 | "closed": "2015-06-04T16:07:03", 8 | "description": "I am having trouble setting the root password on my Linode. I tried following the instructions but something is not working. Can you please help me figure out how I can reset it?", 9 | "entity": { 10 | "id": 10400, 11 | "label": "linode123456", 12 | "type": "linode", 13 | "url": "/v4/linode/instances/123456" 14 | }, 15 | "gravatar_id": "474a1b7373ae0be4132649e69c36ce30", 16 | "id": 11223344, 17 | "opened": "2015-06-04T14:16:44", 18 | "opened_by": "some_user", 19 | "status": "open", 20 | "summary": "Having trouble resetting root password on my Linode", 21 | "updated": "2015-06-04T16:07:03", 22 | "updated_by": "some_other_user" 23 | } -------------------------------------------------------------------------------- /test/unit/fixtures/support_ticket_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "attachments": [ 5 | "screenshot.jpg", 6 | "screenshot.txt" 7 | ], 8 | "closable": false, 9 | "closed": "2015-06-04T16:07:03", 10 | "description": "I am having trouble setting the root password on my Linode. I tried following the instructions but something is not working. Can you please help me figure out how I can reset it?", 11 | "entity": { 12 | "id": 10400, 13 | "label": "linode123456", 14 | "type": "linode", 15 | "url": "/v4/linode/instances/123456" 16 | }, 17 | "gravatar_id": "474a1b7373ae0be4132649e69c36ce30", 18 | "id": 11223344, 19 | "opened": "2015-06-04T14:16:44", 20 | "opened_by": "some_user", 21 | "status": "open", 22 | "summary": "Having trouble resetting root password on my Linode", 23 | "updated": "2015-06-04T16:07:03", 24 | "updated_by": "some_other_user" 25 | } 26 | ], 27 | "page": 1, 28 | "pages": 1, 29 | "results": 1 30 | } -------------------------------------------------------------------------------- /test/unit/fixtures/tag_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "new-tag" 3 | } 4 | -------------------------------------------------------------------------------- /test/unit/fixtures/tagged_objects_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "type": "linode", 5 | "data": { 6 | "id": 12345, 7 | "label": "example-instance", 8 | "region": "us-east" 9 | } 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 1 15 | } -------------------------------------------------------------------------------- /test/unit/fixtures/tags_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "label": "example-tag" 5 | } 6 | ], 7 | "page": 1, 8 | "pages": 1, 9 | "results": 1 10 | } -------------------------------------------------------------------------------- /test/unit/fixtures/vlan_get_ipam_address.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "interfaces": [ 5 | { 6 | "label": "test-vlan", 7 | "ipam_address": "10.0.0.1/24" 8 | } 9 | ] 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 1 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/vlans_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "label": "test-vlan", 5 | "linodes": [12345], 6 | "region": "us-east", 7 | "created": "2024-12-01T12:00:00" 8 | } 9 | ], 10 | "page": 1, 11 | "pages": 1, 12 | "results": 1 13 | } 14 | -------------------------------------------------------------------------------- /test/unit/fixtures/volume_attach.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Test Volume", 4 | "status": "active", 5 | "region": "us-east", 6 | "size": 20, 7 | "linode_id": 456, 8 | "filesystem_path": "/dev/disk/by-id/volume-123", 9 | "tags": ["test"], 10 | "hardware_type": "", 11 | "linode_label": "linode-test", 12 | "encryption": "", 13 | "created": "2025-01-01T12:00:00", 14 | "updated": "2025-01-20T12:00:00" 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/volume_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 124, 3 | "label": "new-volume", 4 | "status": "creating", 5 | "region": "us-east", 6 | "size": 20, 7 | "linode_id": null, 8 | "filesystem_path": "", 9 | "tags": ["test"], 10 | "hardware_type": "", 11 | "linode_label": "", 12 | "encryption": "", 13 | "created": "2025-01-15T12:00:00", 14 | "updated": "2025-01-15T12:00:00" 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/volume_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "Test Volume", 4 | "status": "active", 5 | "region": "us-east", 6 | "size": 20, 7 | "linode_id": null, 8 | "filesystem_path": "", 9 | "tags": ["test"], 10 | "hardware_type": "", 11 | "linode_label": "", 12 | "encryption": "", 13 | "created": "2025-01-01T12:00:00", 14 | "updated": "2025-01-10T12:00:00" 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/volume_types_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "standard", 5 | "label": "Standard Volume", 6 | "price": { 7 | "hourly": 0.10, 8 | "monthly": 10.00 9 | }, 10 | "region_prices": [ 11 | { 12 | "region": "us-east", 13 | "hourly": 0.08, 14 | "monthly": 8.00 15 | } 16 | ] 17 | }, 18 | { 19 | "id": "high-performance", 20 | "label": "High Performance Volume", 21 | "price": { 22 | "hourly": 0.20, 23 | "monthly": 20.00 24 | }, 25 | "region_prices": [ 26 | { 27 | "region": "us-east", 28 | "hourly": 0.18, 29 | "monthly": 18.00 30 | } 31 | ] 32 | } 33 | ], 34 | "pages": 1, 35 | "results": 2 36 | } 37 | -------------------------------------------------------------------------------- /test/unit/fixtures/volume_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "updated-volume", 4 | "status": "active", 5 | "region": "us-east", 6 | "size": 20, 7 | "linode_id": null, 8 | "filesystem_path": "", 9 | "tags": ["updated"], 10 | "hardware_type": "", 11 | "linode_label": "", 12 | "encryption": "", 13 | "created": "2025-01-01T12:00:00", 14 | "updated": "2025-01-18T12:00:00" 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/volumes_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "Test Volume", 6 | "status": "active", 7 | "region": "us-east", 8 | "size": 20, 9 | "linode_id": null, 10 | "filesystem_path": "", 11 | "tags": ["test"], 12 | "hardware_type": "", 13 | "linode_label": "", 14 | "encryption": "", 15 | "created": "2025-01-01T12:00:00", 16 | "updated": "2025-01-10T12:00:00" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "test-vpc", 4 | "description": "Test VPC description", 5 | "region": "us-east", 6 | "subnets": [ 7 | { 8 | "id": 1, 9 | "label": "subnet-1", 10 | "region": "us-east" 11 | }, 12 | { 13 | "id": 2, 14 | "label": "subnet-2", 15 | "region": "us-east" 16 | } 17 | ], 18 | "created": "2023-01-01T12:00:00", 19 | "updated": "2023-01-02T12:00:00" 20 | } 21 | -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "test-vpc", 4 | "description": "Test VPC description", 5 | "region": "us-east", 6 | "subnets": [], 7 | "created": "2023-01-01T12:00:00", 8 | "updated": "2023-01-02T12:00:00" 9 | } -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_ips_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "address": "192.168.1.10", 5 | "vpc_id": 123 6 | }, 7 | { 8 | "address": "192.168.1.11", 9 | "vpc_id": 124 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 2 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "test-vpc", 6 | "description": "Test VPC description", 7 | "region": "us-east", 8 | "subnets": [ 9 | { 10 | "id": 456, 11 | "label": "subnet-1", 12 | "ipv4": "192.168.1.0/24", 13 | "linodes": [] 14 | } 15 | ] 16 | } 17 | ], 18 | "page": 1, 19 | "pages": 1, 20 | "results": 1 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_specific_ips_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "address": "192.168.1.20", 5 | "vpc_id": 123 6 | }, 7 | { 8 | "address": "192.168.1.21", 9 | "vpc_id": 123 10 | } 11 | ], 12 | "page": 1, 13 | "pages": 1, 14 | "results": 2 15 | } 16 | -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_subnet_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 789, 3 | "label": "Test Subnet", 4 | "ipv4": "192.168.1.0/24", 5 | "linodes": [], 6 | "created": "2025-01-01T12:00:00", 7 | "updated": "2025-01-01T12:00:00" 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_subnet_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "label": "Existing Subnet", 4 | "ipv4": "192.168.2.0/24", 5 | "linodes": [ 6 | { 7 | "id": 101, 8 | "interfaces": [ 9 | { 10 | "id": 1, 11 | "active": true 12 | }, 13 | { 14 | "id": 2, 15 | "active": false 16 | } 17 | ] 18 | } 19 | ], 20 | "created": "2025-01-01T10:00:00", 21 | "updated": "2025-01-02T10:00:00" 22 | } -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_subnet_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 456, 3 | "label": "Updated Subnet", 4 | "ipv4": "192.168.2.0/24", 5 | "linodes": [], 6 | "created": "2025-01-01T10:00:00", 7 | "updated": "2025-02-01T10:00:00" 8 | } -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_subnets_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": 123, 5 | "label": "Subnet A", 6 | "ipv4": "192.168.3.0/24" 7 | }, 8 | { 9 | "id": 124, 10 | "label": "Subnet B", 11 | "ipv4": "192.168.4.0/24" 12 | } 13 | ], 14 | "page": 1, 15 | "pages": 1 16 | } 17 | -------------------------------------------------------------------------------- /test/unit/fixtures/vpc_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "label": "updated-vpc", 4 | "description": "Updated description", 5 | "region": "us-east", 6 | "subnets": [], 7 | "created": "2023-01-01T12:00:00", 8 | "updated": "2023-01-02T12:00:00" 9 | } -------------------------------------------------------------------------------- /test/unit/instance_firewall_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestInstanceFirewalls_List(t *testing.T) { 11 | fixtureData, err := fixtures.GetFixture("instance_firewall_list") 12 | assert.NoError(t, err) 13 | 14 | var base ClientBaseCase 15 | base.SetUp(t) 16 | defer base.TearDown(t) 17 | 18 | base.MockGet("linode/instances/123/firewalls", fixtureData) 19 | 20 | firewalls, err := base.Client.ListInstanceFirewalls(context.Background(), 123, nil) 21 | assert.NoError(t, err) 22 | assert.Len(t, firewalls, 2) 23 | 24 | assert.Equal(t, 456, firewalls[0].ID) 25 | assert.Equal(t, "firewall-1", firewalls[0].Label) 26 | 27 | assert.Equal(t, 789, firewalls[1].ID) 28 | assert.Equal(t, "firewall-2", firewalls[1].Label) 29 | } 30 | -------------------------------------------------------------------------------- /test/unit/instance_volume_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestInstanceVolumes_List(t *testing.T) { 12 | fixtureData, err := fixtures.GetFixture("instance_volume_list") 13 | assert.NoError(t, err) 14 | 15 | var base ClientBaseCase 16 | base.SetUp(t) 17 | defer base.TearDown(t) 18 | 19 | base.MockGet("linode/instances/123/volumes", fixtureData) 20 | 21 | volumes, err := base.Client.ListInstanceVolumes(context.Background(), 123, nil) 22 | assert.NoError(t, err) 23 | assert.Len(t, volumes, 2) 24 | 25 | // Validate first volume 26 | assert.Equal(t, 1001, volumes[0].ID) 27 | assert.Equal(t, "volume-1", volumes[0].Label) 28 | assert.Equal(t, 50, volumes[0].Size) 29 | assert.Equal(t, linodego.VolumeStatus("available"), volumes[0].Status) 30 | 31 | // Validate second volume 32 | assert.Equal(t, 1002, volumes[1].ID) 33 | assert.Equal(t, "volume-2", volumes[1].Label) 34 | assert.Equal(t, 100, volumes[1].Size) 35 | assert.Equal(t, linodego.VolumeStatus("resizing"), volumes[1].Status) 36 | } 37 | -------------------------------------------------------------------------------- /test/unit/monitor_services_metrics_definition_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestListMonitorMetricDefinitionsByType(t *testing.T) { 12 | // Load the mock fixture for monitor_service_metrics 13 | fixtureData, err := fixtures.GetFixture("monitor_service_metrics") 14 | assert.NoError(t, err, "Expected no error when getting fixture") 15 | 16 | var base ClientBaseCase 17 | base.SetUp(t) 18 | defer base.TearDown(t) 19 | 20 | // Mock the GET request for the monitor metric-definitions by type (dbaas) 21 | base.MockGet("monitor/services/dbaas/metric-definitions", fixtureData) 22 | 23 | // Call the ListMonitorMetricsDefinitionByServiceType method 24 | clients, err := base.Client.ListMonitorMetricsDefinitionByServiceType(context.Background(), "dbaas", &linodego.ListOptions{}) 25 | assert.NoError(t, err, "Expected no error when listing monitor metric-definitions by type") 26 | assert.NotEmpty(t, clients, "Expected non-empty monitor metric-definitions list") 27 | 28 | assert.Equal(t, "cpu_usage", clients[0].Metric, "Expected Metric to match") 29 | assert.Equal(t, linodego.MetricType("gauge"), clients[0].MetricType, "Expected MetricType to match") 30 | } 31 | -------------------------------------------------------------------------------- /test/unit/monitor_services_token_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestCreateMonitorServicesToken(t *testing.T) { 12 | // Load the mock fixture for monitor services 13 | fixtureData, err := fixtures.GetFixture("monitor_service_token_create") 14 | assert.NoError(t, err) 15 | 16 | var base ClientBaseCase 17 | base.SetUp(t) 18 | defer base.TearDown(t) 19 | 20 | base.MockPost("monitor/services/dbaas/token", fixtureData) 21 | 22 | // Create request data for POST request 23 | opts := linodego.MonitorTokenCreateOptions{ 24 | EntityIDs: []any{12345, "us-54321"}, 25 | } 26 | 27 | token, err := base.Client.CreateMonitorServiceTokenForServiceType(context.Background(), "dbaas", opts) 28 | assert.NoError(t, err) 29 | assert.NotNil(t, token) 30 | } 31 | -------------------------------------------------------------------------------- /test/unit/nodebalancer_firewalls_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestNodeBalancerFirewalls_List(t *testing.T) { 12 | fixtureData, err := fixtures.GetFixture("nodebalancer_firewall_list") 13 | assert.NoError(t, err) 14 | 15 | var base ClientBaseCase 16 | base.SetUp(t) 17 | defer base.TearDown(t) 18 | 19 | // Mock the API response for nodebalancer firewalls 20 | base.MockGet("nodebalancers/123/firewalls", fixtureData) 21 | 22 | firewalls, err := base.Client.ListNodeBalancerFirewalls(context.Background(), 123, nil) 23 | 24 | assert.NoError(t, err) 25 | assert.Len(t, firewalls, 2) 26 | 27 | // Check the details of the first firewall 28 | assert.Equal(t, 789, firewalls[0].ID) 29 | assert.Equal(t, "firewall-1", firewalls[0].Label) 30 | assert.Equal(t, linodego.FirewallStatus("enabled"), firewalls[0].Status) 31 | 32 | // Check the details of the second firewall 33 | assert.Equal(t, 790, firewalls[1].ID) 34 | assert.Equal(t, "firewall-2", firewalls[1].Label) 35 | assert.Equal(t, linodego.FirewallStatus("disabled"), firewalls[1].Status) 36 | } 37 | -------------------------------------------------------------------------------- /test/unit/nodebalancer_stats_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNodeBalancerStats_Get(t *testing.T) { 11 | fixtureData, err := fixtures.GetFixture("nodebalancer_stats_get") 12 | assert.NoError(t, err) 13 | 14 | var base ClientBaseCase 15 | base.SetUp(t) 16 | defer base.TearDown(t) 17 | 18 | base.MockGet("nodebalancers/123/stats", fixtureData) 19 | 20 | stats, err := base.Client.GetNodeBalancerStats(context.Background(), 123) 21 | 22 | // Assertions 23 | assert.NoError(t, err) 24 | assert.NotNil(t, stats) 25 | 26 | assert.Equal(t, "NodeBalancer Stats", stats.Title) 27 | 28 | assert.Len(t, stats.Data.Connections, 2) 29 | assert.Len(t, stats.Data.Connections[0], 2) 30 | 31 | assert.Len(t, stats.Data.Traffic.In, 2) 32 | assert.Len(t, stats.Data.Traffic.Out, 2) 33 | 34 | assert.Equal(t, 1000.0, stats.Data.Traffic.In[0][0]) 35 | assert.Equal(t, 500.0, stats.Data.Traffic.Out[0][0]) 36 | } 37 | -------------------------------------------------------------------------------- /test/unit/object_storage_endpoint_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/linode/linodego" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestObjectStorageEndpoint_List(t *testing.T) { 12 | fixtureData, err := fixtures.GetFixture("object_storage_endpoints_list") 13 | assert.NoError(t, err) 14 | 15 | var base ClientBaseCase 16 | base.SetUp(t) 17 | defer base.TearDown(t) 18 | 19 | base.MockGet("object-storage/endpoints", fixtureData) 20 | 21 | endpoints, err := base.Client.ListObjectStorageEndpoints(context.Background(), nil) 22 | if err != nil { 23 | t.Fatalf("Error getting endpoints: %v", err) 24 | } 25 | 26 | assert.Equal(t, 2, len(endpoints)) 27 | assert.Equal(t, "us-east-1", endpoints[0].Region) 28 | assert.Equal(t, "https://s3.us-east-1.linodeobjects.com", *endpoints[0].S3Endpoint) 29 | assert.Equal(t, linodego.ObjectStorageEndpointE0, endpoints[0].EndpointType) 30 | } 31 | -------------------------------------------------------------------------------- /test/unit/util_test.go: -------------------------------------------------------------------------------- 1 | package unit 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "regexp" 7 | "testing" 8 | 9 | "github.com/linode/linodego" 10 | "github.com/linode/linodego/internal/testutil" 11 | 12 | "github.com/jarcoal/httpmock" 13 | ) 14 | 15 | func mockRequestBodyValidate(t *testing.T, expected interface{}, response interface{}) httpmock.Responder { 16 | return testutil.MockRequestBodyValidate(t, expected, response) 17 | } 18 | 19 | func mockRequestURL(t *testing.T, path string) *regexp.Regexp { 20 | return testutil.MockRequestURL(path) 21 | } 22 | 23 | func createMockClient(t *testing.T) *linodego.Client { 24 | return testutil.CreateMockClient(t, linodego.NewClient) 25 | } 26 | 27 | func formatMockAPIPath(format string, args ...any) string { 28 | escapedArgs := make([]any, len(args)) 29 | for i, arg := range args { 30 | if typeStr, ok := arg.(string); ok { 31 | arg = url.PathEscape(typeStr) 32 | } 33 | 34 | escapedArgs[i] = arg 35 | } 36 | 37 | return fmt.Sprintf(format, escapedArgs...) 38 | } 39 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "fmt" 5 | "runtime/debug" 6 | ) 7 | 8 | const packagePath = "github.com/linode/linodego" 9 | 10 | var ( 11 | Version = "dev" 12 | 13 | // DefaultUserAgent is the default User-Agent sent in HTTP request headers 14 | DefaultUserAgent string 15 | ) 16 | 17 | // init attempts to source the version from the build info injected 18 | // at runtime and sets the DefaultUserAgent. 19 | func init() { 20 | buildInfo, ok := debug.ReadBuildInfo() 21 | if ok { 22 | for _, dep := range buildInfo.Deps { 23 | if dep.Path == packagePath { 24 | if dep.Replace != nil { 25 | Version = dep.Replace.Version 26 | } 27 | Version = dep.Version 28 | break 29 | } 30 | } 31 | } 32 | 33 | DefaultUserAgent = fmt.Sprintf("linodego/%s https://github.com/linode/linodego", Version) 34 | } 35 | -------------------------------------------------------------------------------- /volumes_types.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // VolumeType represents a single valid Volume type. 8 | type VolumeType struct { 9 | baseType[VolumeTypePrice, VolumeTypeRegionPrice] 10 | } 11 | 12 | // VolumeTypePrice represents the base hourly and monthly prices 13 | // for a volume type entry. 14 | type VolumeTypePrice struct { 15 | baseTypePrice 16 | } 17 | 18 | // VolumeTypeRegionPrice represents the regional hourly and monthly prices 19 | // for a volume type entry. 20 | type VolumeTypeRegionPrice struct { 21 | baseTypeRegionPrice 22 | } 23 | 24 | // ListVolumeTypes lists Volume types. This endpoint is cached by default. 25 | func (c *Client) ListVolumeTypes(ctx context.Context, opts *ListOptions) ([]VolumeType, error) { 26 | e := "volumes/types" 27 | 28 | endpoint, err := generateListCacheURL(e, opts) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | if result := c.getCachedResponse(endpoint); result != nil { 34 | return result.([]VolumeType), nil 35 | } 36 | 37 | response, err := getPaginatedResults[VolumeType](ctx, c, e, opts) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | c.addCachedResponse(endpoint, response, &cacheExpiryTime) 43 | 44 | return response, nil 45 | } 46 | -------------------------------------------------------------------------------- /vpc_ips.go: -------------------------------------------------------------------------------- 1 | package linodego 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | // ListAllVPCIPAddresses gets the list of all IP addresses of all VPCs in the Linode account. 9 | func (c *Client) ListAllVPCIPAddresses( 10 | ctx context.Context, opts *ListOptions, 11 | ) ([]VPCIP, error) { 12 | return getPaginatedResults[VPCIP](ctx, c, "vpcs/ips", opts) 13 | } 14 | 15 | // ListVPCIPAddresses gets the list of all IP addresses of a specific VPC. 16 | func (c *Client) ListVPCIPAddresses( 17 | ctx context.Context, vpcID int, opts *ListOptions, 18 | ) ([]VPCIP, error) { 19 | return getPaginatedResults[VPCIP](ctx, c, fmt.Sprintf("vpcs/%d/ips", vpcID), opts) 20 | } 21 | --------------------------------------------------------------------------------