From d48d376e9cfbda6cde455dc89ebdd9578798b8b4 Mon Sep 17 00:00:00 2001 From: Josh Lane Date: Tue, 30 Dec 2014 14:25:09 -0800 Subject: [PATCH] initial import * take the liberty of correcting Aws naming --- fog-aws.gemspec | 4 +- lib/fog/aws.rb | 30 +- lib/fog/aws/auto_scaling.rb | 279 +++++++ lib/fog/aws/beanstalk.rb | 156 ++++ lib/fog/aws/cdn.rb | 205 ++++++ lib/fog/aws/cloud_formation.rb | 133 ++++ lib/fog/aws/cloud_watch.rb | 167 +++++ lib/fog/aws/compute.rb | 543 ++++++++++++++ lib/fog/aws/core.rb | 343 +++++++++ lib/fog/aws/credential_fetcher.rb | 63 ++ lib/fog/aws/data_pipeline.rb | 126 ++++ lib/fog/aws/dns.rb | 154 ++++ lib/fog/aws/dynamodb.rb | 152 ++++ lib/fog/aws/elasticache.rb | 216 ++++++ lib/fog/aws/elb.rb | 240 ++++++ lib/fog/aws/elb/policy_types.rb | 477 ++++++++++++ lib/fog/aws/emr.rb | 139 ++++ lib/fog/aws/glacier.rb | 179 +++++ lib/fog/aws/iam.rb | 260 +++++++ lib/fog/aws/models/auto_scaling/activities.rb | 37 + lib/fog/aws/models/auto_scaling/activity.rb | 27 + .../aws/models/auto_scaling/configuration.rb | 69 ++ .../aws/models/auto_scaling/configurations.rb | 33 + lib/fog/aws/models/auto_scaling/group.rb | 150 ++++ lib/fog/aws/models/auto_scaling/groups.rb | 37 + lib/fog/aws/models/auto_scaling/instance.rb | 58 ++ lib/fog/aws/models/auto_scaling/instances.rb | 28 + lib/fog/aws/models/auto_scaling/policies.rb | 37 + lib/fog/aws/models/auto_scaling/policy.rb | 46 ++ lib/fog/aws/models/beanstalk/application.rb | 59 ++ lib/fog/aws/models/beanstalk/applications.rb | 23 + lib/fog/aws/models/beanstalk/environment.rb | 145 ++++ lib/fog/aws/models/beanstalk/environments.rb | 27 + lib/fog/aws/models/beanstalk/event.rb | 18 + lib/fog/aws/models/beanstalk/events.rb | 17 + lib/fog/aws/models/beanstalk/template.rb | 76 ++ lib/fog/aws/models/beanstalk/templates.rb | 68 ++ lib/fog/aws/models/beanstalk/version.rb | 77 ++ lib/fog/aws/models/beanstalk/versions.rb | 29 + lib/fog/aws/models/cdn/distribution.rb | 90 +++ lib/fog/aws/models/cdn/distribution_helper.rb | 60 ++ lib/fog/aws/models/cdn/distributions.rb | 30 + .../aws/models/cdn/distributions_helper.rb | 45 ++ lib/fog/aws/models/cdn/invalidation.rb | 60 ++ lib/fog/aws/models/cdn/invalidations.rb | 50 ++ .../aws/models/cdn/streaming_distribution.rb | 74 ++ .../aws/models/cdn/streaming_distributions.rb | 30 + lib/fog/aws/models/cloud_watch/alarm.rb | 60 ++ lib/fog/aws/models/cloud_watch/alarm_data.rb | 38 + lib/fog/aws/models/cloud_watch/alarm_datum.rb | 65 ++ .../aws/models/cloud_watch/alarm_histories.rb | 17 + .../aws/models/cloud_watch/alarm_history.rb | 15 + lib/fog/aws/models/cloud_watch/alarms.rb | 45 ++ lib/fog/aws/models/cloud_watch/metric.rb | 13 + .../models/cloud_watch/metric_statistic.rb | 44 ++ .../models/cloud_watch/metric_statistics.rb | 22 + lib/fog/aws/models/cloud_watch/metrics.rb | 50 ++ lib/fog/aws/models/compute/address.rb | 74 ++ lib/fog/aws/models/compute/addresses.rb | 96 +++ lib/fog/aws/models/compute/dhcp_option.rb | 66 ++ lib/fog/aws/models/compute/dhcp_options.rb | 87 +++ lib/fog/aws/models/compute/flavor.rb | 19 + lib/fog/aws/models/compute/flavors.rb | 606 +++++++++++++++ lib/fog/aws/models/compute/image.rb | 45 ++ lib/fog/aws/models/compute/images.rb | 59 ++ .../aws/models/compute/internet_gateway.rb | 78 ++ .../aws/models/compute/internet_gateways.rb | 87 +++ lib/fog/aws/models/compute/key_pair.rb | 53 ++ lib/fog/aws/models/compute/key_pairs.rb | 84 +++ lib/fog/aws/models/compute/network_acl.rb | 180 +++++ lib/fog/aws/models/compute/network_acls.rb | 136 ++++ .../aws/models/compute/network_interface.rb | 73 ++ .../aws/models/compute/network_interfaces.rb | 133 ++++ lib/fog/aws/models/compute/route_table.rb | 66 ++ lib/fog/aws/models/compute/route_tables.rb | 88 +++ lib/fog/aws/models/compute/security_group.rb | 322 ++++++++ lib/fog/aws/models/compute/security_groups.rb | 117 +++ lib/fog/aws/models/compute/server.rb | 271 +++++++ lib/fog/aws/models/compute/servers.rb | 211 ++++++ lib/fog/aws/models/compute/snapshot.rb | 53 ++ lib/fog/aws/models/compute/snapshots.rb | 48 ++ lib/fog/aws/models/compute/spot_request.rb | 119 +++ lib/fog/aws/models/compute/spot_requests.rb | 86 +++ lib/fog/aws/models/compute/subnet.rb | 61 ++ lib/fog/aws/models/compute/subnets.rb | 95 +++ lib/fog/aws/models/compute/tag.rb | 31 + lib/fog/aws/models/compute/tags.rb | 31 + lib/fog/aws/models/compute/volume.rb | 126 ++++ lib/fog/aws/models/compute/volumes.rb | 117 +++ lib/fog/aws/models/compute/vpc.rb | 75 ++ lib/fog/aws/models/compute/vpcs.rb | 89 +++ lib/fog/aws/models/data_pipeline/pipeline.rb | 63 ++ lib/fog/aws/models/data_pipeline/pipelines.rb | 33 + lib/fog/aws/models/dns/record.rb | 116 +++ lib/fog/aws/models/dns/records.rb | 120 +++ lib/fog/aws/models/dns/zone.rb | 49 ++ lib/fog/aws/models/dns/zones.rb | 29 + lib/fog/aws/models/elasticache/cluster.rb | 69 ++ lib/fog/aws/models/elasticache/clusters.rb | 29 + .../aws/models/elasticache/parameter_group.rb | 28 + .../models/elasticache/parameter_groups.rb | 28 + .../aws/models/elasticache/security_group.rb | 48 ++ .../aws/models/elasticache/security_groups.rb | 28 + .../aws/models/elasticache/subnet_group.rb | 32 + .../aws/models/elasticache/subnet_groups.rb | 24 + .../models/elb/backend_server_description.rb | 11 + .../models/elb/backend_server_descriptions.rb | 20 + lib/fog/aws/models/elb/listener.rb | 56 ++ lib/fog/aws/models/elb/listeners.rb | 30 + lib/fog/aws/models/elb/load_balancer.rb | 241 ++++++ lib/fog/aws/models/elb/load_balancers.rb | 37 + lib/fog/aws/models/elb/policies.rb | 52 ++ lib/fog/aws/models/elb/policy.rb | 59 ++ lib/fog/aws/models/glacier/archive.rb | 68 ++ lib/fog/aws/models/glacier/archives.rb | 26 + lib/fog/aws/models/glacier/job.rb | 61 ++ lib/fog/aws/models/glacier/jobs.rb | 40 + lib/fog/aws/models/glacier/vault.rb | 50 ++ lib/fog/aws/models/glacier/vaults.rb | 24 + lib/fog/aws/models/iam/access_key.rb | 39 + lib/fog/aws/models/iam/access_keys.rb | 32 + lib/fog/aws/models/iam/policies.rb | 40 + lib/fog/aws/models/iam/policy.rb | 36 + lib/fog/aws/models/iam/role.rb | 34 + lib/fog/aws/models/iam/roles.rb | 37 + lib/fog/aws/models/iam/user.rb | 38 + lib/fog/aws/models/iam/users.rb | 47 ++ lib/fog/aws/models/rds/event_subscription.rb | 41 ++ lib/fog/aws/models/rds/event_subscriptions.rb | 24 + lib/fog/aws/models/rds/instance_option.rb | 18 + lib/fog/aws/models/rds/instance_options.rb | 28 + lib/fog/aws/models/rds/log_file.rb | 22 + lib/fog/aws/models/rds/log_files.rb | 48 ++ lib/fog/aws/models/rds/parameter.rb | 18 + lib/fog/aws/models/rds/parameter_group.rb | 34 + lib/fog/aws/models/rds/parameter_groups.rb | 24 + lib/fog/aws/models/rds/parameters.rb | 36 + lib/fog/aws/models/rds/security_group.rb | 79 ++ lib/fog/aws/models/rds/security_groups.rb | 41 ++ lib/fog/aws/models/rds/server.rb | 142 ++++ lib/fog/aws/models/rds/servers.rb | 24 + lib/fog/aws/models/rds/snapshot.rb | 49 ++ lib/fog/aws/models/rds/snapshots.rb | 69 ++ lib/fog/aws/models/rds/subnet_group.rb | 31 + lib/fog/aws/models/rds/subnet_groups.rb | 24 + lib/fog/aws/models/sns/subscription.rb | 0 lib/fog/aws/models/sns/subscriptions.rb | 17 + lib/fog/aws/models/sns/topic.rb | 48 ++ lib/fog/aws/models/sns/topics.rb | 24 + lib/fog/aws/models/storage/directories.rb | 39 + lib/fog/aws/models/storage/directory.rb | 126 ++++ lib/fog/aws/models/storage/file.rb | 280 +++++++ lib/fog/aws/models/storage/files.rb | 119 +++ lib/fog/aws/models/storage/version.rb | 33 + lib/fog/aws/models/storage/versions.rb | 34 + lib/fog/aws/parsers/auto_scaling/basic.rb | 24 + .../auto_scaling/describe_adjustment_types.rb | 49 ++ .../describe_auto_scaling_groups.rb | 156 ++++ .../describe_auto_scaling_instances.rb | 40 + ...escribe_auto_scaling_notification_types.rb | 40 + .../describe_launch_configurations.rb | 97 +++ .../describe_metric_collection_types.rb | 64 ++ .../describe_notification_configurations.rb | 39 + .../parsers/auto_scaling/describe_policies.rb | 65 ++ .../describe_scaling_activities.rb | 44 ++ .../describe_scaling_process_types.rb | 49 ++ .../describe_scheduled_actions.rb | 43 ++ .../aws/parsers/auto_scaling/describe_tags.rb | 42 ++ .../describe_termination_policy_types.rb | 40 + .../put_notification_configuration.rb | 24 + .../auto_scaling/put_scaling_policy.rb | 27 + ...erminate_instance_in_auto_scaling_group.rb | 32 + .../beanstalk/check_dns_availability.rb | 16 + .../parsers/beanstalk/create_application.rb | 21 + .../beanstalk/create_application_version.rb | 23 + .../create_configuration_template.rb | 26 + .../parsers/beanstalk/create_environment.rb | 34 + .../beanstalk/create_storage_location.rb | 15 + .../describe_application_versions.rb | 23 + .../beanstalk/describe_applications.rb | 21 + .../describe_configuration_options.rb | 29 + .../describe_configuration_settings.rb | 27 + .../describe_environment_resources.rb | 34 + .../beanstalk/describe_environments.rb | 35 + .../aws/parsers/beanstalk/describe_events.rb | 24 + lib/fog/aws/parsers/beanstalk/empty.rb | 20 + .../list_available_solution_stacks.rb | 18 + lib/fog/aws/parsers/beanstalk/parser.rb | 84 +++ .../beanstalk/retrieve_environment_info.rb | 19 + .../beanstalk/terminate_environment.rb | 34 + .../parsers/beanstalk/update_application.rb | 21 + .../beanstalk/update_application_version.rb | 23 + .../update_configuration_template.rb | 26 + .../parsers/beanstalk/update_environment.rb | 34 + .../validate_configuration_settings.rb | 19 + lib/fog/aws/parsers/cdn/distribution.rb | 55 ++ .../aws/parsers/cdn/get_distribution_list.rb | 57 ++ lib/fog/aws/parsers/cdn/get_invalidation.rb | 28 + .../aws/parsers/cdn/get_invalidation_list.rb | 38 + .../cdn/get_streaming_distribution_list.rb | 55 ++ lib/fog/aws/parsers/cdn/post_invalidation.rb | 24 + .../aws/parsers/cdn/streaming_distribution.rb | 56 ++ lib/fog/aws/parsers/cloud_formation/basic.rb | 10 + .../parsers/cloud_formation/create_stack.rb | 16 + .../cloud_formation/describe_stack_events.rb | 28 + .../describe_stack_resources.rb | 28 + .../cloud_formation/describe_stacks.rb | 78 ++ .../parsers/cloud_formation/get_template.rb | 16 + .../cloud_formation/list_stack_resources.rb | 30 + .../parsers/cloud_formation/list_stacks.rb | 32 + .../parsers/cloud_formation/update_stack.rb | 16 + .../cloud_formation/validate_template.rb | 49 ++ .../aws/parsers/cloud_watch/delete_alarms.rb | 24 + .../cloud_watch/describe_alarm_history.rb | 38 + .../parsers/cloud_watch/describe_alarms.rb | 71 ++ .../cloud_watch/describe_alarms_for_metric.rb | 69 ++ .../cloud_watch/disable_alarm_actions.rb | 24 + .../cloud_watch/enable_alarm_actions.rb | 24 + .../cloud_watch/get_metric_statistics.rb | 40 + .../aws/parsers/cloud_watch/list_metrics.rb | 56 ++ .../parsers/cloud_watch/put_metric_alarm.rb | 24 + .../parsers/cloud_watch/put_metric_data.rb | 24 + .../parsers/cloud_watch/set_alarm_state.rb | 24 + .../aws/parsers/compute/allocate_address.rb | 16 + .../compute/assign_private_ip_addresses.rb | 22 + .../aws/parsers/compute/associate_address.rb | 22 + .../parsers/compute/associate_route_table.rb | 16 + .../compute/attach_network_interface.rb | 16 + lib/fog/aws/parsers/compute/attach_volume.rb | 18 + lib/fog/aws/parsers/compute/basic.rb | 22 + .../compute/cancel_spot_instance_requests.rb | 26 + lib/fog/aws/parsers/compute/copy_image.rb | 18 + lib/fog/aws/parsers/compute/copy_snapshot.rb | 18 + .../parsers/compute/create_dhcp_options.rb | 73 ++ lib/fog/aws/parsers/compute/create_image.rb | 16 + .../compute/create_internet_gateway.rb | 61 ++ .../aws/parsers/compute/create_key_pair.rb | 16 + .../aws/parsers/compute/create_network_acl.rb | 28 + .../compute/create_network_interface.rb | 28 + .../aws/parsers/compute/create_route_table.rb | 71 ++ .../parsers/compute/create_security_group.rb | 22 + .../aws/parsers/compute/create_snapshot.rb | 22 + lib/fog/aws/parsers/compute/create_subnet.rb | 46 ++ lib/fog/aws/parsers/compute/create_volume.rb | 22 + lib/fog/aws/parsers/compute/create_vpc.rb | 47 ++ .../aws/parsers/compute/deregister_image.rb | 16 + .../compute/describe_account_attributes.rb | 41 ++ .../aws/parsers/compute/describe_addresses.rb | 26 + .../compute/describe_availability_zones.rb | 40 + .../parsers/compute/describe_dhcp_options.rb | 72 ++ .../aws/parsers/compute/describe_images.rb | 89 +++ .../compute/describe_instance_status.rb | 73 ++ .../aws/parsers/compute/describe_instances.rb | 122 ++++ .../compute/describe_internet_gateways.rb | 60 ++ .../aws/parsers/compute/describe_key_pairs.rb | 26 + .../parsers/compute/describe_network_acls.rb | 42 ++ .../describe_network_interface_attribute.rb | 77 ++ .../compute/describe_network_interfaces.rb | 42 ++ .../compute/describe_placement_groups.rb | 26 + .../aws/parsers/compute/describe_regions.rb | 26 + .../compute/describe_reserved_instances.rb | 58 ++ .../describe_reserved_instances_offerings.rb | 30 + .../parsers/compute/describe_route_tables.rb | 81 +++ .../compute/describe_security_groups.rb | 111 +++ .../aws/parsers/compute/describe_snapshots.rb | 52 ++ .../compute/describe_spot_price_history.rb | 30 + .../aws/parsers/compute/describe_subnets.rb | 49 ++ lib/fog/aws/parsers/compute/describe_tags.rb | 26 + .../parsers/compute/describe_volume_status.rb | 87 +++ .../aws/parsers/compute/describe_volumes.rb | 71 ++ .../parsers/compute/describe_vpc_attribute.rb | 48 ++ lib/fog/aws/parsers/compute/describe_vpcs.rb | 47 ++ lib/fog/aws/parsers/compute/detach_volume.rb | 18 + .../aws/parsers/compute/get_console_output.rb | 24 + .../aws/parsers/compute/get_password_data.rb | 22 + .../aws/parsers/compute/import_key_pair.rb | 16 + .../compute/modify_subnet_attribute.rb | 24 + .../compute/monitor_unmonitor_instances.rb | 31 + .../aws/parsers/compute/network_acl_parser.rb | 103 +++ .../compute/network_interface_parser.rb | 108 +++ .../purchase_reserved_instances_offering.rb | 20 + lib/fog/aws/parsers/compute/register_image.rb | 16 + .../replace_network_acl_association.rb | 20 + lib/fog/aws/parsers/compute/run_instances.rb | 90 +++ .../compute/spot_datafeed_subscription.rb | 25 + .../parsers/compute/spot_instance_requests.rb | 69 ++ .../parsers/compute/start_stop_instances.rb | 37 + .../parsers/compute/terminate_instances.rb | 51 ++ .../dns/change_resource_record_sets.rb | 22 + .../aws/parsers/dns/create_health_check.rb | 0 lib/fog/aws/parsers/dns/create_hosted_zone.rb | 51 ++ lib/fog/aws/parsers/dns/delete_hosted_zone.rb | 21 + lib/fog/aws/parsers/dns/get_change.rb | 22 + lib/fog/aws/parsers/dns/get_hosted_zone.rb | 41 ++ lib/fog/aws/parsers/dns/health_check.rb | 33 + lib/fog/aws/parsers/dns/list_health_checks.rb | 41 ++ lib/fog/aws/parsers/dns/list_hosted_zones.rb | 33 + .../parsers/dns/list_resource_record_sets.rb | 58 ++ .../authorize_cache_security_group_ingress.rb | 21 + lib/fog/aws/parsers/elasticache/base.rb | 28 + .../elasticache/cache_cluster_parser.rb | 77 ++ .../elasticache/create_cache_subnet_group.rb | 32 + .../elasticache/describe_cache_clusters.rb | 26 + .../elasticache/describe_cache_parameters.rb | 21 + .../describe_cache_subnet_groups.rb | 34 + .../describe_engine_default_parameters.rb | 21 + .../elasticache/describe_parameter_groups.rb | 26 + .../describe_reserved_cache_nodes.rb | 32 + .../elasticache/describe_security_groups.rb | 26 + .../elasticache/engine_defaults_parser.rb | 58 ++ lib/fog/aws/parsers/elasticache/event_list.rb | 38 + .../elasticache/modify_parameter_group.rb | 26 + .../elasticache/parameter_group_parser.rb | 29 + .../elasticache/reset_parameter_group.rb | 26 + .../elasticache/security_group_parser.rb | 38 + .../elasticache/single_cache_cluster.rb | 21 + .../elasticache/single_parameter_group.rb | 21 + .../elasticache/single_security_group.rb | 33 + .../elasticache/subnet_group_parser.rb | 35 + .../apply_security_groups_to_load_balancer.rb | 22 + .../elb/attach_load_balancer_to_subnets.rb | 22 + .../aws/parsers/elb/configure_health_check.rb | 33 + .../aws/parsers/elb/create_load_balancer.rb | 22 + .../aws/parsers/elb/delete_load_balancer.rb | 20 + ...deregister_instances_from_load_balancer.rb | 22 + .../parsers/elb/describe_instance_health.rb | 26 + .../elb/describe_load_balancer_attributes.rb | 54 ++ .../elb/describe_load_balancer_policies.rb | 60 ++ .../describe_load_balancer_policy_types.rb | 66 ++ .../parsers/elb/describe_load_balancers.rb | 167 +++++ lib/fog/aws/parsers/elb/describe_tags.rb | 26 + .../elb/detach_load_balancer_from_subnets.rb | 22 + ...le_availability_zones_for_load_balancer.rb | 22 + lib/fog/aws/parsers/elb/empty.rb | 24 + ...le_availability_zones_for_load_balancer.rb | 22 + .../register_instances_with_load_balancer.rb | 22 + lib/fog/aws/parsers/elb/tag_list_parser.rb | 57 ++ .../aws/parsers/emr/add_instance_groups.rb | 26 + lib/fog/aws/parsers/emr/add_job_flow_steps.rb | 16 + lib/fog/aws/parsers/emr/describe_job_flows.rb | 137 ++++ .../aws/parsers/emr/modify_instance_groups.rb | 16 + lib/fog/aws/parsers/emr/run_job_flow.rb | 18 + .../parsers/emr/set_termination_protection.rb | 16 + .../aws/parsers/emr/terminate_job_flows.rb | 16 + .../aws/parsers/iam/base_instance_profile.rb | 75 ++ lib/fog/aws/parsers/iam/basic.rb | 16 + lib/fog/aws/parsers/iam/create_access_key.rb | 22 + lib/fog/aws/parsers/iam/create_group.rb | 22 + lib/fog/aws/parsers/iam/create_user.rb | 22 + .../iam/get_account_password_policy.rb | 26 + .../aws/parsers/iam/get_account_summary.rb | 42 ++ lib/fog/aws/parsers/iam/get_group.rb | 52 ++ lib/fog/aws/parsers/iam/get_group_policy.rb | 30 + lib/fog/aws/parsers/iam/get_role_policy.rb | 28 + lib/fog/aws/parsers/iam/get_user.rb | 26 + lib/fog/aws/parsers/iam/get_user_policy.rb | 30 + lib/fog/aws/parsers/iam/instance_profile.rb | 28 + lib/fog/aws/parsers/iam/list_access_keys.rb | 28 + .../aws/parsers/iam/list_account_aliases.rb | 24 + lib/fog/aws/parsers/iam/list_groups.rb | 28 + .../aws/parsers/iam/list_groups_for_user.rb | 28 + .../aws/parsers/iam/list_instance_profiles.rb | 29 + lib/fog/aws/parsers/iam/list_mfa_devices.rb | 30 + lib/fog/aws/parsers/iam/list_policies.rb | 24 + lib/fog/aws/parsers/iam/list_roles.rb | 29 + .../parsers/iam/list_server_certificates.rb | 34 + .../parsers/iam/list_signing_certificates.rb | 28 + lib/fog/aws/parsers/iam/list_users.rb | 30 + lib/fog/aws/parsers/iam/login_profile.rb | 24 + lib/fog/aws/parsers/iam/role_parser.rb | 49 ++ lib/fog/aws/parsers/iam/single_role.rb | 27 + lib/fog/aws/parsers/iam/update_group.rb | 23 + lib/fog/aws/parsers/iam/update_user.rb | 24 + .../parsers/iam/upload_server_certificate.rb | 24 + .../parsers/iam/upload_signing_certificate.rb | 22 + .../authorize_db_security_group_ingress.rb | 32 + lib/fog/aws/parsers/rds/base.rb | 28 + lib/fog/aws/parsers/rds/create_db_instance.rb | 32 + .../rds/create_db_instance_read_replica.rb | 32 + .../parsers/rds/create_db_parameter_group.rb | 33 + .../parsers/rds/create_db_security_group.rb | 32 + lib/fog/aws/parsers/rds/create_db_snapshot.rb | 32 + .../aws/parsers/rds/create_db_subnet_group.rb | 32 + .../parsers/rds/create_event_subscription.rb | 32 + .../parsers/rds/db_engine_version_parser.rb | 32 + lib/fog/aws/parsers/rds/db_parser.rb | 136 ++++ lib/fog/aws/parsers/rds/delete_db_instance.rb | 33 + .../parsers/rds/delete_db_parameter_group.rb | 25 + .../parsers/rds/delete_db_security_group.rb | 29 + lib/fog/aws/parsers/rds/delete_db_snapshot.rb | 32 + .../aws/parsers/rds/delete_db_subnet_group.rb | 29 + .../parsers/rds/delete_event_subscription.rb | 29 + .../rds/describe_db_engine_versions.rb | 34 + .../aws/parsers/rds/describe_db_instances.rb | 34 + .../aws/parsers/rds/describe_db_log_files.rb | 42 ++ .../rds/describe_db_parameter_groups.rb | 33 + .../aws/parsers/rds/describe_db_parameters.rb | 42 ++ .../rds/describe_db_reserved_instances.rb | 38 + .../rds/describe_db_security_groups.rb | 34 + .../aws/parsers/rds/describe_db_snapshots.rb | 34 + .../parsers/rds/describe_db_subnet_groups.rb | 34 + .../rds/describe_event_subscriptions.rb | 34 + .../describe_orderable_db_instance_options.rb | 45 ++ .../rds/download_db_logfile_portion.rb | 22 + lib/fog/aws/parsers/rds/event_list.rb | 38 + .../parsers/rds/event_subscription_parser.rb | 37 + lib/fog/aws/parsers/rds/modify_db_instance.rb | 32 + .../parsers/rds/modify_db_parameter_group.rb | 26 + .../aws/parsers/rds/promote_read_replica.rb | 32 + lib/fog/aws/parsers/rds/reboot_db_instance.rb | 33 + .../restore_db_instance_from_db_snapshot.rb | 32 + .../restore_db_instance_to_point_in_time.rb | 32 + .../rds/revoke_db_security_group_ingress.rb | 32 + .../aws/parsers/rds/security_group_parser.rb | 36 + lib/fog/aws/parsers/rds/snapshot_parser.rb | 39 + .../aws/parsers/rds/subnet_group_parser.rb | 35 + lib/fog/aws/parsers/rds/tag_list_parser.rb | 33 + lib/fog/aws/parsers/redshift/cluster.rb | 28 + .../aws/parsers/redshift/cluster_parser.rb | 143 ++++ .../redshift/cluster_security_group_parser.rb | 49 ++ .../aws/parsers/redshift/cluster_snapshot.rb | 31 + .../redshift/cluster_snapshot_parser.rb | 65 ++ .../redshift/cluster_subnet_group_parser.rb | 50 ++ .../create_cluster_parameter_group.rb | 29 + .../redshift/create_cluster_security_group.rb | 30 + .../describe_cluster_parameter_groups.rb | 40 + .../redshift/describe_cluster_parameters.rb | 47 ++ .../describe_cluster_security_groups.rb | 37 + .../redshift/describe_cluster_snapshots.rb | 37 + .../describe_cluster_subnet_groups.rb | 55 ++ .../redshift/describe_cluster_versions.rb | 50 ++ .../aws/parsers/redshift/describe_clusters.rb | 29 + .../describe_default_cluster_parameters.rb | 48 ++ .../aws/parsers/redshift/describe_events.rb | 43 ++ .../describe_orderable_cluster_options.rb | 53 ++ .../describe_reserved_node_offerings.rb | 63 ++ .../redshift/describe_reserved_nodes.rb | 70 ++ .../aws/parsers/redshift/describe_resize.rb | 58 ++ .../purchase_reserved_node_offering.rb | 56 ++ .../revoke_cluster_security_group_ingress.rb | 30 + .../update_cluster_parameter_group_parser.rb | 28 + .../ses/delete_verified_email_address.rb | 20 + lib/fog/aws/parsers/ses/get_send_quota.rb | 22 + .../aws/parsers/ses/get_send_statistics.rb | 26 + .../ses/list_verified_email_addresses.rb | 22 + lib/fog/aws/parsers/ses/send_email.rb | 22 + lib/fog/aws/parsers/ses/send_raw_email.rb | 22 + .../aws/parsers/ses/verify_domain_identity.rb | 22 + .../aws/parsers/ses/verify_email_address.rb | 20 + lib/fog/aws/parsers/simpledb/basic.rb | 27 + .../aws/parsers/simpledb/domain_metadata.rb | 28 + .../aws/parsers/simpledb/get_attributes.rb | 32 + lib/fog/aws/parsers/simpledb/list_domains.rb | 26 + lib/fog/aws/parsers/simpledb/select.rb | 37 + lib/fog/aws/parsers/sns/add_permission.rb | 20 + .../aws/parsers/sns/confirm_subscription.rb | 20 + lib/fog/aws/parsers/sns/create_topic.rb | 20 + lib/fog/aws/parsers/sns/delete_topic.rb | 20 + .../aws/parsers/sns/get_topic_attributes.rb | 29 + lib/fog/aws/parsers/sns/list_subscriptions.rb | 26 + lib/fog/aws/parsers/sns/list_topics.rb | 22 + lib/fog/aws/parsers/sns/publish.rb | 20 + lib/fog/aws/parsers/sns/remove_permission.rb | 20 + .../aws/parsers/sns/set_topic_attributes.rb | 20 + lib/fog/aws/parsers/sns/subscribe.rb | 20 + lib/fog/aws/parsers/sns/unsubscribe.rb | 20 + lib/fog/aws/parsers/sqs/basic.rb | 20 + lib/fog/aws/parsers/sqs/create_queue.rb | 22 + .../aws/parsers/sqs/get_queue_attributes.rb | 31 + lib/fog/aws/parsers/sqs/list_queues.rb | 22 + lib/fog/aws/parsers/sqs/receive_message.rb | 37 + lib/fog/aws/parsers/sqs/send_message.rb | 24 + .../parsers/storage/access_control_list.rb | 42 ++ .../storage/complete_multipart_upload.rb | 20 + lib/fog/aws/parsers/storage/copy_object.rb | 18 + .../aws/parsers/storage/cors_configuration.rb | 38 + .../storage/delete_multiple_objects.rb | 45 ++ lib/fog/aws/parsers/storage/get_bucket.rb | 58 ++ .../parsers/storage/get_bucket_lifecycle.rb | 64 ++ .../parsers/storage/get_bucket_location.rb | 16 + .../aws/parsers/storage/get_bucket_logging.rb | 36 + .../storage/get_bucket_object_versions.rb | 84 +++ .../aws/parsers/storage/get_bucket_tagging.rb | 33 + .../parsers/storage/get_bucket_versioning.rb | 20 + .../aws/parsers/storage/get_bucket_website.rb | 26 + .../parsers/storage/get_request_payment.rb | 16 + lib/fog/aws/parsers/storage/get_service.rb | 28 + .../storage/initiate_multipart_upload.rb | 20 + .../parsers/storage/list_multipart_uploads.rb | 52 ++ lib/fog/aws/parsers/storage/list_parts.rb | 36 + lib/fog/aws/parsers/sts/assume_role.rb | 26 + .../aws/parsers/sts/assume_role_with_saml.rb | 26 + lib/fog/aws/parsers/sts/get_session_token.rb | 26 + lib/fog/aws/rds.rb | 269 +++++++ lib/fog/aws/redshift.rb | 133 ++++ lib/fog/aws/region_methods.rb | 11 + .../auto_scaling/create_auto_scaling_group.rb | 140 ++++ .../create_launch_configuration.rb | 114 +++ .../auto_scaling/create_or_update_tags.rb | 57 ++ .../auto_scaling/delete_auto_scaling_group.rb | 55 ++ .../delete_launch_configuration.rb | 51 ++ .../delete_notification_configuration.rb | 58 ++ .../requests/auto_scaling/delete_policy.rb | 50 ++ .../auto_scaling/delete_scheduled_action.rb | 42 ++ .../aws/requests/auto_scaling/delete_tags.rb | 57 ++ .../auto_scaling/describe_adjustment_types.rb | 48 ++ .../describe_auto_scaling_groups.rb | 134 ++++ .../describe_auto_scaling_instances.rb | 89 +++ ...escribe_auto_scaling_notification_types.rb | 50 ++ .../describe_launch_configurations.rb | 112 +++ .../describe_metric_collection_types.rb | 56 ++ .../describe_notification_configurations.rb | 73 ++ .../auto_scaling/describe_policies.rb | 105 +++ .../describe_scaling_activities.rb | 82 +++ .../describe_scaling_process_types.rb | 49 ++ .../describe_scheduled_actions.rb | 82 +++ .../requests/auto_scaling/describe_tags.rb | 68 ++ .../describe_termination_policy_types.rb | 47 ++ .../disable_metrics_collection.rb | 50 ++ .../auto_scaling/enable_metrics_collection.rb | 60 ++ .../requests/auto_scaling/execute_policy.rb | 44 ++ .../put_notification_configuration.rb | 64 ++ .../auto_scaling/put_scaling_policy.rb | 79 ++ .../put_scheduled_update_group_action.rb | 64 ++ .../requests/auto_scaling/resume_processes.rb | 53 ++ .../auto_scaling/set_desired_capacity.rb | 81 +++ .../auto_scaling/set_instance_health.rb | 49 ++ .../auto_scaling/suspend_processes.rb | 56 ++ ...erminate_instance_in_auto_scaling_group.rb | 59 ++ .../auto_scaling/update_auto_scaling_group.rb | 93 +++ .../beanstalk/check_dns_availability.rb | 26 + .../requests/beanstalk/create_application.rb | 28 + .../beanstalk/create_application_version.rb | 40 + .../create_configuration_template.rb | 46 ++ .../requests/beanstalk/create_environment.rb | 49 ++ .../beanstalk/create_storage_location.rb | 26 + .../requests/beanstalk/delete_application.rb | 28 + .../beanstalk/delete_application_version.rb | 35 + .../delete_configuration_template.rb | 33 + .../delete_environment_configuration.rb | 33 + .../describe_application_versions.rb | 33 + .../beanstalk/describe_applications.rb | 29 + .../describe_configuration_options.rb | 39 + .../describe_configuration_settings.rb | 30 + .../describe_environment_resources.rb | 28 + .../beanstalk/describe_environments.rb | 39 + .../aws/requests/beanstalk/describe_events.rb | 28 + .../list_available_solution_stacks.rb | 26 + .../requests/beanstalk/rebuild_environment.rb | 29 + .../beanstalk/request_environment_info.rb | 28 + .../requests/beanstalk/restart_app_server.rb | 28 + .../beanstalk/retrieve_environment_info.rb | 28 + .../beanstalk/swap_environment_cnames.rb | 28 + .../beanstalk/terminate_environment.rb | 30 + .../requests/beanstalk/update_application.rb | 29 + .../beanstalk/update_application_version.rb | 29 + .../update_configuration_template.rb | 35 + .../requests/beanstalk/update_environment.rb | 41 ++ .../validate_configuration_settings.rb | 32 + .../aws/requests/cdn/delete_distribution.rb | 52 ++ .../cdn/delete_streaming_distribution.rb | 51 ++ lib/fog/aws/requests/cdn/get_distribution.rb | 78 ++ .../aws/requests/cdn/get_distribution_list.rb | 81 +++ lib/fog/aws/requests/cdn/get_invalidation.rb | 58 ++ .../aws/requests/cdn/get_invalidation_list.rb | 76 ++ .../cdn/get_streaming_distribution.rb | 69 ++ .../cdn/get_streaming_distribution_list.rb | 81 +++ lib/fog/aws/requests/cdn/post_distribution.rb | 130 ++++ lib/fog/aws/requests/cdn/post_invalidation.rb | 75 ++ .../cdn/post_streaming_distribution.rb | 115 +++ .../requests/cdn/put_distribution_config.rb | 116 +++ .../cdn/put_streaming_distribution_config.rb | 105 +++ .../requests/cloud_formation/create_stack.rb | 88 +++ .../requests/cloud_formation/delete_stack.rb | 25 + .../cloud_formation/describe_stack_events.rb | 39 + .../describe_stack_resources.rb | 38 + .../cloud_formation/describe_stacks.rb | 37 + .../requests/cloud_formation/get_template.rb | 27 + .../cloud_formation/list_stack_resources.rb | 34 + .../requests/cloud_formation/list_stacks.rb | 35 + .../requests/cloud_formation/update_stack.rb | 56 ++ .../cloud_formation/validate_template.rb | 29 + .../aws/requests/cloud_watch/delete_alarms.rb | 47 ++ .../cloud_watch/describe_alarm_history.rb | 32 + .../requests/cloud_watch/describe_alarms.rb | 55 ++ .../cloud_watch/describe_alarms_for_metric.rb | 38 + .../cloud_watch/disable_alarm_actions.rb | 29 + .../cloud_watch/enable_alarm_actions.rb | 29 + .../cloud_watch/get_metric_statistics.rb | 46 ++ .../aws/requests/cloud_watch/list_metrics.rb | 62 ++ .../requests/cloud_watch/put_metric_alarm.rb | 93 +++ .../requests/cloud_watch/put_metric_data.rb | 72 ++ .../requests/cloud_watch/set_alarm_state.rb | 30 + .../aws/requests/compute/allocate_address.rb | 55 ++ .../compute/assign_private_ip_addresses.rb | 55 ++ .../aws/requests/compute/associate_address.rb | 126 ++++ .../compute/associate_dhcp_options.rb | 53 ++ .../requests/compute/associate_route_table.rb | 70 ++ .../compute/attach_internet_gateway.rb | 52 ++ .../compute/attach_network_interface.rb | 61 ++ lib/fog/aws/requests/compute/attach_volume.rb | 83 +++ .../authorize_security_group_ingress.rb | 230 ++++++ .../compute/cancel_spot_instance_requests.rb | 32 + lib/fog/aws/requests/compute/copy_image.rb | 59 ++ lib/fog/aws/requests/compute/copy_snapshot.rb | 54 ++ .../requests/compute/create_dhcp_options.rb | 74 ++ lib/fog/aws/requests/compute/create_image.rb | 91 +++ .../compute/create_internet_gateway.rb | 52 ++ .../aws/requests/compute/create_key_pair.rb | 52 ++ .../requests/compute/create_network_acl.rb | 105 +++ .../compute/create_network_acl_entry.rb | 80 ++ .../compute/create_network_interface.rb | 134 ++++ .../compute/create_placement_group.rb | 31 + lib/fog/aws/requests/compute/create_route.rb | 87 +++ .../requests/compute/create_route_table.rb | 69 ++ .../requests/compute/create_security_group.rb | 60 ++ .../aws/requests/compute/create_snapshot.rb | 70 ++ .../create_spot_datafeed_subscription.rb | 39 + lib/fog/aws/requests/compute/create_subnet.rb | 102 +++ lib/fog/aws/requests/compute/create_tags.rb | 65 ++ lib/fog/aws/requests/compute/create_volume.rb | 124 ++++ lib/fog/aws/requests/compute/create_vpc.rb | 94 +++ .../requests/compute/delete_dhcp_options.rb | 50 ++ .../compute/delete_internet_gateway.rb | 48 ++ .../aws/requests/compute/delete_key_pair.rb | 43 ++ .../requests/compute/delete_network_acl.rb | 52 ++ .../compute/delete_network_acl_entry.rb | 55 ++ .../compute/delete_network_interface.rb | 51 ++ .../compute/delete_placement_group.rb | 30 + lib/fog/aws/requests/compute/delete_route.rb | 57 ++ .../requests/compute/delete_route_table.rb | 49 ++ .../requests/compute/delete_security_group.rb | 100 +++ .../aws/requests/compute/delete_snapshot.rb | 46 ++ .../delete_spot_datafeed_subscription.rb | 26 + lib/fog/aws/requests/compute/delete_subnet.rb | 49 ++ lib/fog/aws/requests/compute/delete_tags.rb | 67 ++ lib/fog/aws/requests/compute/delete_volume.rb | 52 ++ lib/fog/aws/requests/compute/delete_vpc.rb | 56 ++ .../aws/requests/compute/deregister_image.rb | 49 ++ .../compute/describe_account_attributes.rb | 48 ++ .../requests/compute/describe_addresses.rb | 62 ++ .../compute/describe_availability_zones.rb | 94 +++ .../requests/compute/describe_dhcp_options.rb | 54 ++ .../aws/requests/compute/describe_images.rb | 126 ++++ .../compute/describe_instance_status.rb | 46 ++ .../requests/compute/describe_instances.rb | 265 +++++++ .../compute/describe_internet_gateways.rb | 59 ++ .../requests/compute/describe_key_pairs.rb | 64 ++ .../requests/compute/describe_network_acls.rb | 108 +++ .../describe_network_interface_attribute.rb | 66 ++ .../compute/describe_network_interfaces.rb | 85 +++ .../compute/describe_placement_groups.rb | 33 + .../aws/requests/compute/describe_regions.rb | 64 ++ .../compute/describe_reserved_instances.rb | 59 ++ .../describe_reserved_instances_offerings.rb | 80 ++ .../requests/compute/describe_route_tables.rb | 86 +++ .../compute/describe_security_groups.rb | 98 +++ .../requests/compute/describe_snapshots.rb | 120 +++ .../describe_spot_datafeed_subscription.rb | 33 + .../describe_spot_instance_requests.rb | 46 ++ .../compute/describe_spot_price_history.rb | 35 + .../aws/requests/compute/describe_subnets.rb | 71 ++ lib/fog/aws/requests/compute/describe_tags.rb | 104 +++ .../compute/describe_volume_status.rb | 43 ++ .../aws/requests/compute/describe_volumes.rb | 118 +++ .../compute/describe_vpc_attribute.rb | 55 ++ lib/fog/aws/requests/compute/describe_vpcs.rb | 74 ++ .../compute/detach_internet_gateway.rb | 52 ++ .../compute/detach_network_interface.rb | 48 ++ lib/fog/aws/requests/compute/detach_volume.rb | 61 ++ .../requests/compute/disassociate_address.rb | 55 ++ .../compute/disassociate_route_table.rb | 54 ++ .../requests/compute/get_console_output.rb | 50 ++ .../aws/requests/compute/get_password_data.rb | 52 ++ .../aws/requests/compute/import_key_pair.rb | 52 ++ .../compute/modify_image_attribute.rb | 70 ++ .../compute/modify_instance_attribute.rb | 42 ++ .../modify_network_interface_attribute.rb | 89 +++ .../compute/modify_snapshot_attribute.rb | 35 + .../compute/modify_subnet_attribute.rb | 58 ++ .../compute/modify_volume_attribute.rb | 48 ++ .../requests/compute/modify_vpc_attribute.rb | 66 ++ .../aws/requests/compute/monitor_instances.rb | 48 ++ .../purchase_reserved_instances_offering.rb | 62 ++ .../aws/requests/compute/reboot_instances.rb | 50 ++ .../aws/requests/compute/register_image.rb | 133 ++++ .../aws/requests/compute/release_address.rb | 59 ++ .../replace_network_acl_association.rb | 66 ++ .../compute/replace_network_acl_entry.rb | 81 +++ lib/fog/aws/requests/compute/replace_route.rb | 80 ++ .../compute/request_spot_instances.rb | 96 +++ .../reset_network_interface_attribute.rb | 56 ++ .../compute/revoke_security_group_ingress.rb | 98 +++ lib/fog/aws/requests/compute/run_instances.rb | 274 +++++++ .../aws/requests/compute/start_instances.rb | 58 ++ .../aws/requests/compute/stop_instances.rb | 59 ++ .../requests/compute/terminate_instances.rb | 92 +++ .../requests/compute/unmonitor_instances.rb | 48 ++ .../data_pipeline/activate_pipeline.rb | 31 + .../requests/data_pipeline/create_pipeline.rb | 39 + .../requests/data_pipeline/delete_pipeline.rb | 30 + .../data_pipeline/describe_objects.rb | 38 + .../data_pipeline/describe_pipelines.rb | 32 + .../data_pipeline/get_pipeline_definition.rb | 33 + .../requests/data_pipeline/list_pipelines.rb | 32 + .../data_pipeline/put_pipeline_definition.rb | 76 ++ .../requests/data_pipeline/query_objects.rb | 38 + .../dns/change_resource_record_sets.rb | 243 +++++++ .../aws/requests/dns/create_health_check.rb | 64 ++ .../aws/requests/dns/create_hosted_zone.rb | 108 +++ .../aws/requests/dns/delete_health_check.rb | 24 + .../aws/requests/dns/delete_hosted_zone.rb | 66 ++ lib/fog/aws/requests/dns/get_change.rb | 59 ++ lib/fog/aws/requests/dns/get_health_check.rb | 41 ++ lib/fog/aws/requests/dns/get_hosted_zone.rb | 61 ++ .../aws/requests/dns/list_health_checks.rb | 36 + lib/fog/aws/requests/dns/list_hosted_zones.rb | 88 +++ .../requests/dns/list_resource_record_sets.rb | 130 ++++ .../aws/requests/dynamodb/batch_get_item.rb | 41 ++ .../aws/requests/dynamodb/batch_write_item.rb | 33 + lib/fog/aws/requests/dynamodb/create_table.rb | 53 ++ lib/fog/aws/requests/dynamodb/delete_item.rb | 43 ++ lib/fog/aws/requests/dynamodb/delete_table.rb | 40 + .../aws/requests/dynamodb/describe_table.rb | 42 ++ lib/fog/aws/requests/dynamodb/get_item.rb | 41 ++ lib/fog/aws/requests/dynamodb/list_tables.rb | 27 + lib/fog/aws/requests/dynamodb/put_item.rb | 39 + lib/fog/aws/requests/dynamodb/query.rb | 42 ++ lib/fog/aws/requests/dynamodb/scan.rb | 43 ++ lib/fog/aws/requests/dynamodb/update_item.rb | 47 ++ lib/fog/aws/requests/dynamodb/update_table.rb | 44 ++ .../authorize_cache_security_group_ingress.rb | 57 ++ .../elasticache/create_cache_cluster.rb | 94 +++ .../create_cache_parameter_group.rb | 52 ++ .../create_cache_security_group.rb | 51 ++ .../elasticache/create_cache_subnet_group.rb | 60 ++ .../elasticache/delete_cache_cluster.rb | 38 + .../delete_cache_parameter_group.rb | 40 + .../delete_cache_security_group.rb | 39 + .../elasticache/delete_cache_subnet_group.rb | 39 + .../elasticache/describe_cache_clusters.rb | 51 ++ .../describe_cache_parameter_groups.rb | 47 ++ .../elasticache/describe_cache_parameters.rb | 34 + .../describe_cache_security_groups.rb | 64 ++ .../describe_cache_subnet_groups.rb | 59 ++ .../describe_engine_default_parameters.rb | 33 + .../requests/elasticache/describe_events.rb | 47 ++ .../describe_reserved_cache_nodes.rb | 38 + .../elasticache/modify_cache_cluster.rb | 99 +++ .../modify_cache_parameter_group.rb | 43 ++ .../elasticache/reboot_cache_cluster.rb | 49 ++ .../reset_cache_parameter_group.rb | 44 ++ .../revoke_cache_security_group_ingress.rb | 35 + lib/fog/aws/requests/elb/add_tags.rb | 46 ++ .../apply_security_groups_to_load_balancer.rb | 58 ++ .../elb/attach_load_balancer_to_subnets.rb | 58 ++ .../requests/elb/configure_health_check.rb | 63 ++ .../create_app_cookie_stickiness_policy.rb | 52 ++ .../elb/create_lb_cookie_stickiness_policy.rb | 54 ++ .../aws/requests/elb/create_load_balancer.rb | 206 ++++++ .../elb/create_load_balancer_listeners.rb | 86 +++ .../elb/create_load_balancer_policy.rb | 80 ++ .../aws/requests/elb/delete_load_balancer.rb | 49 ++ .../elb/delete_load_balancer_listeners.rb | 48 ++ .../elb/delete_load_balancer_policy.rb | 52 ++ ...deregister_instances_from_load_balancer.rb | 61 ++ .../requests/elb/describe_instance_health.rb | 70 ++ .../elb/describe_load_balancer_attributes.rb | 58 ++ .../elb/describe_load_balancer_policies.rb | 69 ++ .../describe_load_balancer_policy_types.rb | 66 ++ .../requests/elb/describe_load_balancers.rb | 137 ++++ lib/fog/aws/requests/elb/describe_tags.rb | 56 ++ .../elb/detach_load_balancer_from_subnets.rb | 58 ++ ...le_availability_zones_for_load_balancer.rb | 57 ++ ...le_availability_zones_for_load_balancer.rb | 58 ++ .../elb/modify_load_balancer_attributes.rb | 65 ++ .../register_instances_with_load_balancer.rb | 62 ++ lib/fog/aws/requests/elb/remove_tags.rb | 46 ++ ..._load_balancer_listener_ssl_certificate.rb | 65 ++ ...ad_balancer_policies_for_backend_server.rb | 66 ++ .../set_load_balancer_policies_of_listener.rb | 78 ++ .../aws/requests/emr/add_instance_groups.rb | 42 ++ .../aws/requests/emr/add_job_flow_steps.rb | 45 ++ .../aws/requests/emr/describe_job_flows.rb | 104 +++ .../requests/emr/modify_instance_groups.rb | 36 + lib/fog/aws/requests/emr/run_job_flow.rb | 104 +++ .../emr/set_termination_protection.rb | 35 + .../aws/requests/emr/terminate_job_flows.rb | 33 + .../glacier/abort_multipart_upload.rb | 33 + .../glacier/complete_multipart_upload.rb | 40 + .../aws/requests/glacier/create_archive.rb | 41 ++ lib/fog/aws/requests/glacier/create_vault.rb | 32 + .../aws/requests/glacier/delete_archive.rb | 33 + lib/fog/aws/requests/glacier/delete_vault.rb | 32 + ...delete_vault_notification_configuration.rb | 31 + lib/fog/aws/requests/glacier/describe_job.rb | 33 + .../aws/requests/glacier/describe_vault.rb | 32 + .../aws/requests/glacier/get_job_output.rb | 39 + .../get_vault_notification_configuration.rb | 32 + lib/fog/aws/requests/glacier/initiate_job.rb | 39 + .../glacier/initiate_multipart_upload.rb | 36 + lib/fog/aws/requests/glacier/list_jobs.rb | 36 + .../glacier/list_multipart_uploads.rb | 34 + lib/fog/aws/requests/glacier/list_parts.rb | 35 + lib/fog/aws/requests/glacier/list_vaults.rb | 34 + .../set_vault_notification_configuration.rb | 35 + lib/fog/aws/requests/glacier/upload_part.rb | 44 ++ .../iam/add_role_to_instance_profile.rb | 32 + lib/fog/aws/requests/iam/add_user_to_group.rb | 54 ++ lib/fog/aws/requests/iam/create_access_key.rb | 66 ++ .../aws/requests/iam/create_account_alias.rb | 17 + lib/fog/aws/requests/iam/create_group.rb | 56 ++ .../requests/iam/create_instance_profile.rb | 45 ++ .../aws/requests/iam/create_login_profile.rb | 34 + lib/fog/aws/requests/iam/create_role.rb | 55 ++ lib/fog/aws/requests/iam/create_user.rb | 59 ++ lib/fog/aws/requests/iam/delete_access_key.rb | 47 ++ .../aws/requests/iam/delete_account_alias.rb | 17 + .../iam/delete_account_password_policy.rb | 36 + lib/fog/aws/requests/iam/delete_group.rb | 48 ++ .../aws/requests/iam/delete_group_policy.rb | 32 + .../requests/iam/delete_instance_profile.rb | 30 + .../aws/requests/iam/delete_login_profile.rb | 29 + lib/fog/aws/requests/iam/delete_role.rb | 30 + .../aws/requests/iam/delete_role_policy.rb | 32 + .../requests/iam/delete_server_certificate.rb | 46 ++ .../iam/delete_signing_certificate.rb | 31 + lib/fog/aws/requests/iam/delete_user.rb | 44 ++ .../aws/requests/iam/delete_user_policy.rb | 46 ++ .../iam/get_account_password_policy.rb | 36 + .../aws/requests/iam/get_account_summary.rb | 75 ++ lib/fog/aws/requests/iam/get_group.rb | 60 ++ lib/fog/aws/requests/iam/get_group_policy.rb | 51 ++ .../aws/requests/iam/get_instance_profile.rb | 40 + lib/fog/aws/requests/iam/get_login_profile.rb | 33 + lib/fog/aws/requests/iam/get_role.rb | 36 + lib/fog/aws/requests/iam/get_role_policy.rb | 34 + .../requests/iam/get_server_certificate.rb | 45 ++ lib/fog/aws/requests/iam/get_user.rb | 55 ++ lib/fog/aws/requests/iam/get_user_policy.rb | 51 ++ lib/fog/aws/requests/iam/list_access_keys.rb | 62 ++ .../aws/requests/iam/list_account_aliases.rb | 16 + .../aws/requests/iam/list_group_policies.rb | 37 + lib/fog/aws/requests/iam/list_groups.rb | 57 ++ .../aws/requests/iam/list_groups_for_user.rb | 65 ++ .../requests/iam/list_instance_profiles.rb | 48 ++ .../iam/list_instance_profiles_for_role.rb | 49 ++ lib/fog/aws/requests/iam/list_mfa_devices.rb | 55 ++ .../aws/requests/iam/list_role_policies.rb | 37 + lib/fog/aws/requests/iam/list_roles.rb | 41 ++ .../requests/iam/list_server_certificates.rb | 54 ++ .../requests/iam/list_signing_certificates.rb | 36 + .../aws/requests/iam/list_user_policies.rb | 53 ++ lib/fog/aws/requests/iam/list_users.rb | 58 ++ lib/fog/aws/requests/iam/put_group_policy.rb | 50 ++ lib/fog/aws/requests/iam/put_role_policy.rb | 34 + lib/fog/aws/requests/iam/put_user_policy.rb | 51 ++ .../iam/remove_role_from_instance_profile.rb | 33 + .../requests/iam/remove_user_from_group.rb | 50 ++ lib/fog/aws/requests/iam/update_access_key.rb | 55 ++ .../iam/update_account_password_policy.rb | 56 ++ lib/fog/aws/requests/iam/update_group.rb | 37 + .../aws/requests/iam/update_login_profile.rb | 31 + .../requests/iam/update_server_certificate.rb | 63 ++ .../iam/update_signing_certificate.rb | 31 + lib/fog/aws/requests/iam/update_user.rb | 37 + .../requests/iam/upload_server_certificate.rb | 95 +++ .../iam/upload_signing_certificate.rb | 36 + .../aws/requests/rds/add_tags_to_resource.rb | 42 ++ .../authorize_db_security_group_ingress.rb | 65 ++ .../aws/requests/rds/create_db_instance.rb | 132 ++++ .../rds/create_db_instance_read_replica.rb | 77 ++ .../requests/rds/create_db_parameter_group.rb | 53 ++ .../requests/rds/create_db_security_group.rb | 49 ++ .../aws/requests/rds/create_db_snapshot.rb | 68 ++ .../requests/rds/create_db_subnet_group.rb | 61 ++ .../requests/rds/create_event_subscription.rb | 67 ++ .../aws/requests/rds/delete_db_instance.rb | 51 ++ .../requests/rds/delete_db_parameter_group.rb | 41 ++ .../requests/rds/delete_db_security_group.rb | 40 + .../aws/requests/rds/delete_db_snapshot.rb | 42 ++ .../requests/rds/delete_db_subnet_group.rb | 38 + .../requests/rds/delete_event_subscription.rb | 44 ++ .../rds/describe_db_engine_versions.rb | 30 + .../aws/requests/rds/describe_db_instances.rb | 89 +++ .../aws/requests/rds/describe_db_log_files.rb | 64 ++ .../rds/describe_db_parameter_groups.rb | 58 ++ .../requests/rds/describe_db_parameters.rb | 42 ++ .../rds/describe_db_reserved_instances.rb | 38 + .../rds/describe_db_security_groups.rb | 80 ++ .../aws/requests/rds/describe_db_snapshots.rb | 66 ++ .../requests/rds/describe_db_subnet_groups.rb | 59 ++ .../rds/describe_event_subscriptions.rb | 61 ++ lib/fog/aws/requests/rds/describe_events.rb | 50 ++ .../describe_orderable_db_instance_options.rb | 72 ++ .../rds/download_db_logfile_portion.rb | 58 ++ .../requests/rds/list_tags_for_resource.rb | 40 + .../aws/requests/rds/modify_db_instance.rb | 81 +++ .../requests/rds/modify_db_parameter_group.rb | 50 ++ .../aws/requests/rds/promote_read_replica.rb | 59 ++ .../aws/requests/rds/reboot_db_instance.rb | 47 ++ .../requests/rds/remove_tags_from_resource.rb | 40 + .../restore_db_instance_from_db_snapshot.rb | 29 + .../restore_db_instance_to_point_in_time.rb | 29 + .../rds/revoke_db_security_group_ingress.rb | 63 ++ ...uthorize_cluster_security_group_ingress.rb | 54 ++ .../redshift/authorize_snapshot_access.rb | 42 ++ .../redshift/copy_cluster_snapshot.rb | 46 ++ .../aws/requests/redshift/create_cluster.rb | 148 ++++ .../create_cluster_parameter_group.rb | 53 ++ .../redshift/create_cluster_security_group.rb | 41 ++ .../redshift/create_cluster_snapshot.rb | 43 ++ .../redshift/create_cluster_subnet_group.rb | 49 ++ .../aws/requests/redshift/delete_cluster.rb | 50 ++ .../delete_cluster_parameter_group.rb | 33 + .../redshift/delete_cluster_security_group.rb | 32 + .../redshift/delete_cluster_snapshot.rb | 43 ++ .../redshift/delete_cluster_subnet_group.rb | 36 + .../describe_cluster_parameter_groups.rb | 47 ++ .../redshift/describe_cluster_parameters.rb | 54 ++ .../describe_cluster_security_groups.rb | 49 ++ .../redshift/describe_cluster_snapshots.rb | 72 ++ .../describe_cluster_subnet_groups.rb | 46 ++ .../redshift/describe_cluster_versions.rb | 53 ++ .../requests/redshift/describe_clusters.rb | 49 ++ .../describe_default_cluster_parameters.rb | 48 ++ .../aws/requests/redshift/describe_events.rb | 79 ++ .../describe_orderable_cluster_options.rb | 54 ++ .../describe_reserved_node_offerings.rb | 47 ++ .../redshift/describe_reserved_nodes.rb | 47 ++ .../aws/requests/redshift/describe_resize.rb | 38 + .../aws/requests/redshift/modify_cluster.rb | 109 +++ .../modify_cluster_parameter_group.rb | 44 ++ .../redshift/modify_cluster_subnet_group.rb | 49 ++ .../purchase_reserved_node_offering.rb | 39 + .../aws/requests/redshift/reboot_cluster.rb | 36 + .../redshift/reset_cluster_parameter_group.rb | 55 ++ .../redshift/restore_from_cluster_snapshot.rb | 76 ++ .../revoke_cluster_security_group_ingress.rb | 54 ++ .../redshift/revoke_snapshot_access.rb | 43 ++ .../ses/delete_verified_email_address.rb | 26 + lib/fog/aws/requests/ses/get_send_quota.rb | 29 + .../aws/requests/ses/get_send_statistics.rb | 32 + .../ses/list_verified_email_addresses.rb | 26 + lib/fog/aws/requests/ses/send_email.rb | 71 ++ lib/fog/aws/requests/ses/send_raw_email.rb | 39 + .../requests/ses/verify_domain_identity.rb | 28 + .../aws/requests/ses/verify_email_address.rb | 26 + .../requests/simpledb/batch_put_attributes.rb | 60 ++ .../aws/requests/simpledb/create_domain.rb | 40 + .../requests/simpledb/delete_attributes.rb | 69 ++ .../aws/requests/simpledb/delete_domain.rb | 41 ++ .../aws/requests/simpledb/domain_metadata.rb | 72 ++ .../aws/requests/simpledb/get_attributes.rb | 80 ++ lib/fog/aws/requests/simpledb/list_domains.rb | 55 ++ .../aws/requests/simpledb/put_attributes.rb | 74 ++ lib/fog/aws/requests/simpledb/select.rb | 41 ++ lib/fog/aws/requests/sns/add_permission.rb | 22 + .../aws/requests/sns/confirm_subscription.rb | 30 + lib/fog/aws/requests/sns/create_topic.rb | 47 ++ lib/fog/aws/requests/sns/delete_topic.rb | 36 + .../aws/requests/sns/get_topic_attributes.rb | 36 + .../aws/requests/sns/list_subscriptions.rb | 35 + .../sns/list_subscriptions_by_topic.rb | 39 + lib/fog/aws/requests/sns/list_topics.rb | 35 + lib/fog/aws/requests/sns/publish.rb | 31 + lib/fog/aws/requests/sns/remove_permission.rb | 22 + .../aws/requests/sns/set_topic_attributes.rb | 45 ++ lib/fog/aws/requests/sns/subscribe.rb | 85 +++ lib/fog/aws/requests/sns/unsubscribe.rb | 26 + .../requests/sqs/change_message_visibility.rb | 58 ++ lib/fog/aws/requests/sqs/create_queue.rb | 62 ++ lib/fog/aws/requests/sqs/delete_message.rb | 56 ++ lib/fog/aws/requests/sqs/delete_queue.rb | 47 ++ .../aws/requests/sqs/get_queue_attributes.rb | 48 ++ lib/fog/aws/requests/sqs/list_queues.rb | 41 ++ lib/fog/aws/requests/sqs/receive_message.rb | 83 +++ lib/fog/aws/requests/sqs/send_message.rb | 65 ++ .../aws/requests/sqs/set_queue_attributes.rb | 49 ++ .../storage/abort_multipart_upload.rb | 45 ++ lib/fog/aws/requests/storage/acl_utils.rb | 60 ++ .../storage/complete_multipart_upload.rb | 73 ++ lib/fog/aws/requests/storage/copy_object.rb | 77 ++ lib/fog/aws/requests/storage/cors_utils.rb | 39 + lib/fog/aws/requests/storage/delete_bucket.rb | 42 ++ .../requests/storage/delete_bucket_cors.rb | 26 + .../storage/delete_bucket_lifecycle.rb | 26 + .../requests/storage/delete_bucket_policy.rb | 26 + .../requests/storage/delete_bucket_tagging.rb | 41 ++ .../requests/storage/delete_bucket_website.rb | 26 + .../storage/delete_multiple_objects.rb | 164 +++++ lib/fog/aws/requests/storage/delete_object.rb | 115 +++ lib/fog/aws/requests/storage/get_bucket.rb | 108 +++ .../aws/requests/storage/get_bucket_acl.rb | 65 ++ .../aws/requests/storage/get_bucket_cors.rb | 61 ++ .../requests/storage/get_bucket_lifecycle.rb | 35 + .../requests/storage/get_bucket_location.rb | 55 ++ .../requests/storage/get_bucket_logging.rb | 45 ++ .../storage/get_bucket_object_versions.rb | 160 ++++ .../aws/requests/storage/get_bucket_policy.rb | 31 + .../requests/storage/get_bucket_tagging.rb | 49 ++ .../requests/storage/get_bucket_versioning.rb | 68 ++ .../requests/storage/get_bucket_website.rb | 38 + lib/fog/aws/requests/storage/get_object.rb | 189 +++++ .../aws/requests/storage/get_object_acl.rb | 76 ++ .../requests/storage/get_object_http_url.rb | 30 + .../requests/storage/get_object_https_url.rb | 30 + .../requests/storage/get_object_torrent.rb | 45 ++ .../aws/requests/storage/get_object_url.rb | 40 + .../requests/storage/get_request_payment.rb | 45 ++ lib/fog/aws/requests/storage/get_service.rb | 50 ++ lib/fog/aws/requests/storage/head_bucket.rb | 38 + lib/fog/aws/requests/storage/head_object.rb | 62 ++ .../storage/initiate_multipart_upload.rb | 66 ++ .../storage/list_multipart_uploads.rb | 52 ++ lib/fog/aws/requests/storage/list_parts.rb | 53 ++ .../storage/post_object_hidden_fields.rb | 54 ++ .../requests/storage/post_object_restore.rb | 50 ++ lib/fog/aws/requests/storage/put_bucket.rb | 73 ++ .../aws/requests/storage/put_bucket_acl.rb | 69 ++ .../aws/requests/storage/put_bucket_cors.rb | 47 ++ .../requests/storage/put_bucket_lifecycle.rb | 76 ++ .../requests/storage/put_bucket_logging.rb | 80 ++ .../aws/requests/storage/put_bucket_policy.rb | 25 + .../requests/storage/put_bucket_tagging.rb | 55 ++ .../requests/storage/put_bucket_versioning.rb | 74 ++ .../requests/storage/put_bucket_website.rb | 87 +++ lib/fog/aws/requests/storage/put_object.rb | 87 +++ .../aws/requests/storage/put_object_acl.rb | 78 ++ .../aws/requests/storage/put_object_url.rb | 41 ++ .../requests/storage/put_request_payment.rb | 45 ++ .../requests/storage/shared_mock_methods.rb | 87 +++ lib/fog/aws/requests/storage/sync_clock.rb | 24 + lib/fog/aws/requests/storage/upload_part.rb | 57 ++ lib/fog/aws/requests/sts/assume_role.rb | 44 ++ .../aws/requests/sts/assume_role_with_saml.rb | 44 ++ .../aws/requests/sts/get_federation_token.rb | 62 ++ lib/fog/aws/requests/sts/get_session_token.rb | 18 + lib/fog/aws/ses.rb | 141 ++++ lib/fog/aws/signaturev4.rb | 119 +++ lib/fog/aws/simpledb.rb | 211 ++++++ lib/fog/aws/sns.rb | 160 ++++ lib/fog/aws/sqs.rb | 164 +++++ lib/fog/aws/storage.rb | 687 ++++++++++++++++++ lib/fog/aws/sts.rb | 185 +++++ lib/fog/aws/version.rb | 2 +- tests/credentials_tests.rb | 55 ++ tests/helper.rb | 21 + tests/helpers/collection_helper.rb | 97 +++ tests/helpers/compute/flavors_helper.rb | 32 + tests/helpers/compute/server_helper.rb | 25 + tests/helpers/compute/servers_helper.rb | 10 + tests/helpers/dns_helper.rb | 55 ++ tests/helpers/formats_helper.rb | 98 +++ tests/helpers/formats_helper_tests.rb | 110 +++ tests/helpers/mock_helper.rb | 110 +++ tests/helpers/model_helper.rb | 31 + tests/helpers/responds_to_helper.rb | 11 + tests/helpers/schema_validator_tests.rb | 107 +++ tests/helpers/succeeds_helper.rb | 9 + tests/models/auto_scaling/activities_tests.rb | 6 + .../models/auto_scaling/configuration_test.rb | 13 + .../auto_scaling/configurations_tests.rb | 11 + tests/models/auto_scaling/groups_test.rb | 27 + tests/models/auto_scaling/helper.rb | 0 tests/models/auto_scaling/instance_tests.rb | 15 + tests/models/auto_scaling/instances_tests.rb | 6 + tests/models/beanstalk/application_tests.rb | 69 ++ tests/models/beanstalk/applications_tests.rb | 7 + tests/models/beanstalk/environment_tests.rb | 131 ++++ tests/models/beanstalk/environments_tests.rb | 34 + tests/models/beanstalk/template_tests.rb | 47 ++ tests/models/beanstalk/templates_tests.rb | 62 ++ tests/models/beanstalk/version_tests.rb | 66 ++ tests/models/beanstalk/versions_tests.rb | 60 ++ tests/models/cdn/distribution_tests.rb | 15 + tests/models/cdn/distributions_tests.rb | 15 + tests/models/cdn/invalidation_tests.rb | 31 + tests/models/cdn/invalidations_tests.rb | 14 + .../cdn/streaming_distribution_tests.rb | 15 + .../cdn/streaming_distributions_tests.rb | 15 + tests/models/cloud_watch/alarm_data_tests.rb | 42 ++ .../models/cloud_watch/alarm_history_tests.rb | 22 + .../cloud_watch/metric_statistics_tests.rb | 51 ++ tests/models/cloud_watch/metrics_tests.rb | 32 + tests/models/compute/address_tests.rb | 24 + tests/models/compute/addresses_tests.rb | 5 + tests/models/compute/dhcp_option_tests.rb | 3 + tests/models/compute/dhcp_options_tests.rb | 3 + .../models/compute/internet_gateway_tests.rb | 3 + .../models/compute/internet_gateways_tests.rb | 3 + tests/models/compute/key_pair_tests.rb | 26 + tests/models/compute/key_pairs_tests.rb | 5 + tests/models/compute/network_acl_tests.rb | 109 +++ tests/models/compute/network_acls_tests.rb | 20 + .../models/compute/network_interfaces_test.rb | 12 + tests/models/compute/security_group_tests.rb | 64 ++ tests/models/compute/security_groups_tests.rb | 5 + tests/models/compute/server_tests.rb | 83 +++ tests/models/compute/snapshot_tests.rb | 10 + tests/models/compute/snapshots_tests.rb | 10 + tests/models/compute/subnet_tests.rb | 5 + tests/models/compute/subnets_tests.rb | 5 + tests/models/compute/volume_tests.rb | 43 ++ tests/models/compute/volumes_tests.rb | 5 + tests/models/compute/vpc_tests.rb | 4 + tests/models/compute/vpcs_tests.rb | 19 + tests/models/data_pipeline/pipeline_tests.rb | 8 + tests/models/data_pipeline/pipelines_tests.rb | 8 + tests/models/dns/record_tests.rb | 33 + tests/models/dns/records_tests.rb | 41 ++ tests/models/dns/zone_tests.rb | 4 + tests/models/dns/zones_tests.rb | 4 + tests/models/elasticache/cluster_tests.rb | 30 + .../elasticache/parameter_groups_tests.rb | 15 + .../elasticache/security_groups_tests.rb | 52 ++ .../models/elasticache/subnet_groups_tests.rb | 44 ++ tests/models/elb/model_tests.rb | 360 +++++++++ tests/models/elb/tagging_tests.rb | 15 + tests/models/glacier/model_tests.rb | 47 ++ tests/models/iam/access_keys_tests.rb | 53 ++ tests/models/iam/policies_tests.rb | 57 ++ tests/models/iam/roles_tests.rb | 63 ++ tests/models/iam/users_tests.rb | 71 ++ tests/models/rds/event_subscription_tests.rb | 9 + tests/models/rds/event_subscriptions_tests.rb | 6 + tests/models/rds/helper.rb | 5 + tests/models/rds/instance_option_tests.rb | 14 + tests/models/rds/parameter_group_tests.rb | 24 + tests/models/rds/parameter_groups_tests.rb | 8 + tests/models/rds/security_group_tests.rb | 53 ++ tests/models/rds/security_groups_tests.rb | 5 + tests/models/rds/server_tests.rb | 110 +++ tests/models/rds/servers_tests.rb | 6 + tests/models/rds/snapshot_tests.rb | 12 + tests/models/rds/snapshots_tests.rb | 12 + tests/models/rds/tagging_tests.rb | 20 + tests/models/sns/topic_tests.rb | 15 + tests/models/sns/topics_tests.rb | 6 + tests/models/storage/directory_tests.rb | 87 +++ tests/models/storage/file_tests.rb | 92 +++ tests/models/storage/files_tests.rb | 58 ++ tests/models/storage/url_tests.rb | 26 + tests/models/storage/version_tests.rb | 52 ++ tests/models/storage/versions_tests.rb | 56 ++ tests/parsers/elb/describe_load_balancers.rb | 65 ++ .../auto_scaling/auto_scaling_tests.rb | 77 ++ .../auto_scaling/describe_types_tests.rb | 102 +++ tests/requests/auto_scaling/helper.rb | 228 ++++++ tests/requests/auto_scaling/model_tests.rb | 233 ++++++ .../notification_configuration_tests.rb | 124 ++++ tests/requests/auto_scaling/tag_tests.rb | 63 ++ tests/requests/beanstalk/application_tests.rb | 140 ++++ .../beanstalk/solution_stack_tests.rb | 22 + tests/requests/cdn/cdn_tests.rb | 252 +++++++ tests/requests/cloud_formation/stack_tests.rb | 167 +++++ .../get_metric_statistics_tests.rb | 28 + .../requests/cloud_watch/list_metrics_test.rb | 64 ++ .../cloud_watch/put_metric_data_tests.rb | 36 + tests/requests/compute/address_tests.rb | 108 +++ .../compute/assign_private_ip_tests.rb | 55 ++ .../compute/availability_zone_tests.rb | 25 + tests/requests/compute/client_tests.rb | 25 + tests/requests/compute/dhcp_options_tests.rb | 39 + tests/requests/compute/helper.rb | 10 + tests/requests/compute/image_tests.rb | 158 ++++ tests/requests/compute/instance_tests.rb | 297 ++++++++ .../compute/internet_gateway_tests.rb | 49 ++ tests/requests/compute/key_pair_tests.rb | 67 ++ tests/requests/compute/network_acl_tests.rb | 112 +++ .../compute/network_interface_tests.rb | 250 +++++++ .../requests/compute/placement_group_tests.rb | 48 ++ tests/requests/compute/region_tests.rb | 52 ++ tests/requests/compute/route_tests.rb | 339 +++++++++ .../requests/compute/security_group_tests.rb | 437 +++++++++++ tests/requests/compute/snapshot_tests.rb | 77 ++ .../spot_datafeed_subscription_tests.rb | 47 ++ tests/requests/compute/spot_instance_tests.rb | 57 ++ .../compute/spot_price_history_tests.rb | 24 + tests/requests/compute/subnet_tests.rb | 85 +++ tests/requests/compute/tag_tests.rb | 101 +++ tests/requests/compute/volume_tests.rb | 206 ++++++ tests/requests/compute/vpc_tests.rb | 111 +++ tests/requests/data_pipeline/helper.rb | 72 ++ .../requests/data_pipeline/pipeline_tests.rb | 78 ++ tests/requests/dns/dns_tests.rb | 257 +++++++ tests/requests/dns/health_check_tests.rb | 159 ++++ tests/requests/dns/helper.rb | 21 + tests/requests/dynamodb/item_tests.rb | 137 ++++ tests/requests/dynamodb/table_tests.rb | 99 +++ .../elasticache/cache_cluster_tests.rb | 137 ++++ tests/requests/elasticache/describe_events.rb | 17 + .../describe_reserved_cache_nodes.rb | 17 + tests/requests/elasticache/helper.rb | 103 +++ .../elasticache/parameter_group_tests.rb | 105 +++ .../elasticache/security_group_tests.rb | 108 +++ .../elasticache/subnet_group_tests.rb | 52 ++ tests/requests/elb/helper.rb | 91 +++ tests/requests/elb/listener_tests.rb | 68 ++ tests/requests/elb/load_balancer_tests.rb | 89 +++ tests/requests/elb/policy_tests.rb | 132 ++++ tests/requests/emr/helper.rb | 168 +++++ tests/requests/emr/instance_group_tests.rb | 106 +++ tests/requests/emr/job_flow_tests.rb | 88 +++ tests/requests/glacier/archive_tests.rb | 13 + .../glacier/multipart_upload_tests.rb | 29 + tests/requests/glacier/tree_hash_tests.rb | 62 ++ tests/requests/glacier/vault_tests.rb | 35 + tests/requests/iam/access_key_tests.rb | 53 ++ tests/requests/iam/account_policy_tests.rb | 20 + tests/requests/iam/account_tests.rb | 34 + tests/requests/iam/group_policy_tests.rb | 48 ++ tests/requests/iam/group_tests.rb | 44 ++ tests/requests/iam/helper.rb | 102 +++ tests/requests/iam/login_profile_tests.rb | 62 ++ tests/requests/iam/mfa_tests.rb | 23 + tests/requests/iam/role_tests.rb | 167 +++++ .../requests/iam/server_certificate_tests.rb | 130 ++++ tests/requests/iam/user_policy_tests.rb | 45 ++ tests/requests/iam/user_tests.rb | 77 ++ tests/requests/rds/describe_events.rb | 16 + .../requests/rds/event_subscription_tests.rb | 30 + tests/requests/rds/helper.rb | 296 ++++++++ tests/requests/rds/instance_option_tests.rb | 21 + tests/requests/rds/instance_tests.rb | 133 ++++ tests/requests/rds/log_file_tests.rb | 19 + tests/requests/rds/parameter_group_tests.rb | 62 ++ tests/requests/rds/parameter_request_tests.rb | 34 + tests/requests/rds/security_group_tests.rb | 101 +++ tests/requests/rds/subnet_groups_tests.rb | 52 ++ tests/requests/rds/tagging_tests.rb | 78 ++ .../redshift/cluster_parameter_group_tests.rb | 76 ++ .../redshift/cluster_security_group_tests.rb | 42 ++ .../redshift/cluster_snapshot_tests.rb | 73 ++ tests/requests/redshift/cluster_tests.rb | 80 ++ tests/requests/ses/helper.rb | 9 + .../ses/verified_domain_identity_tests.rb | 16 + .../ses/verified_email_address_tests.rb | 27 + tests/requests/simpledb/attributes_tests.rb | 86 +++ tests/requests/simpledb/domain_tests.rb | 51 ++ tests/requests/simpledb/helper.rb | 10 + tests/requests/sns/helper.rb | 9 + tests/requests/sns/subscription_tests.rb | 86 +++ tests/requests/sns/topic_tests.rb | 45 ++ tests/requests/sqs/helper.rb | 9 + tests/requests/sqs/message_tests.rb | 51 ++ tests/requests/sqs/queue_tests.rb | 50 ++ tests/requests/storage/acl_utils_tests.rb | 209 ++++++ tests/requests/storage/bucket_tests.rb | 379 ++++++++++ tests/requests/storage/cors_utils_tests.rb | 108 +++ .../storage/delete_multiple_objects_tests.rb | 12 + .../storage/multipart_upload_tests.rb | 121 +++ tests/requests/storage/object_tests.rb | 189 +++++ tests/requests/storage/versioning_tests.rb | 258 +++++++ tests/requests/sts/assume_role_tests.rb | 19 + .../sts/assume_role_with_saml_tests.rb | 18 + .../sts/get_federation_token_tests.rb | 20 + tests/requests/sts/session_token_tests.rb | 16 + tests/signaturev4_tests.rb | 88 +++ tests/signed_params_tests.rb | 17 + tests/storage_tests.rb | 7 + 1261 files changed, 72105 insertions(+), 5 deletions(-) create mode 100644 lib/fog/aws/auto_scaling.rb create mode 100644 lib/fog/aws/beanstalk.rb create mode 100644 lib/fog/aws/cdn.rb create mode 100644 lib/fog/aws/cloud_formation.rb create mode 100644 lib/fog/aws/cloud_watch.rb create mode 100644 lib/fog/aws/compute.rb create mode 100644 lib/fog/aws/core.rb create mode 100644 lib/fog/aws/credential_fetcher.rb create mode 100644 lib/fog/aws/data_pipeline.rb create mode 100644 lib/fog/aws/dns.rb create mode 100644 lib/fog/aws/dynamodb.rb create mode 100644 lib/fog/aws/elasticache.rb create mode 100644 lib/fog/aws/elb.rb create mode 100644 lib/fog/aws/elb/policy_types.rb create mode 100644 lib/fog/aws/emr.rb create mode 100644 lib/fog/aws/glacier.rb create mode 100644 lib/fog/aws/iam.rb create mode 100644 lib/fog/aws/models/auto_scaling/activities.rb create mode 100644 lib/fog/aws/models/auto_scaling/activity.rb create mode 100644 lib/fog/aws/models/auto_scaling/configuration.rb create mode 100644 lib/fog/aws/models/auto_scaling/configurations.rb create mode 100644 lib/fog/aws/models/auto_scaling/group.rb create mode 100644 lib/fog/aws/models/auto_scaling/groups.rb create mode 100644 lib/fog/aws/models/auto_scaling/instance.rb create mode 100644 lib/fog/aws/models/auto_scaling/instances.rb create mode 100644 lib/fog/aws/models/auto_scaling/policies.rb create mode 100644 lib/fog/aws/models/auto_scaling/policy.rb create mode 100644 lib/fog/aws/models/beanstalk/application.rb create mode 100644 lib/fog/aws/models/beanstalk/applications.rb create mode 100644 lib/fog/aws/models/beanstalk/environment.rb create mode 100644 lib/fog/aws/models/beanstalk/environments.rb create mode 100644 lib/fog/aws/models/beanstalk/event.rb create mode 100644 lib/fog/aws/models/beanstalk/events.rb create mode 100644 lib/fog/aws/models/beanstalk/template.rb create mode 100644 lib/fog/aws/models/beanstalk/templates.rb create mode 100644 lib/fog/aws/models/beanstalk/version.rb create mode 100644 lib/fog/aws/models/beanstalk/versions.rb create mode 100644 lib/fog/aws/models/cdn/distribution.rb create mode 100644 lib/fog/aws/models/cdn/distribution_helper.rb create mode 100644 lib/fog/aws/models/cdn/distributions.rb create mode 100644 lib/fog/aws/models/cdn/distributions_helper.rb create mode 100644 lib/fog/aws/models/cdn/invalidation.rb create mode 100644 lib/fog/aws/models/cdn/invalidations.rb create mode 100644 lib/fog/aws/models/cdn/streaming_distribution.rb create mode 100644 lib/fog/aws/models/cdn/streaming_distributions.rb create mode 100644 lib/fog/aws/models/cloud_watch/alarm.rb create mode 100644 lib/fog/aws/models/cloud_watch/alarm_data.rb create mode 100644 lib/fog/aws/models/cloud_watch/alarm_datum.rb create mode 100644 lib/fog/aws/models/cloud_watch/alarm_histories.rb create mode 100644 lib/fog/aws/models/cloud_watch/alarm_history.rb create mode 100644 lib/fog/aws/models/cloud_watch/alarms.rb create mode 100644 lib/fog/aws/models/cloud_watch/metric.rb create mode 100644 lib/fog/aws/models/cloud_watch/metric_statistic.rb create mode 100644 lib/fog/aws/models/cloud_watch/metric_statistics.rb create mode 100644 lib/fog/aws/models/cloud_watch/metrics.rb create mode 100644 lib/fog/aws/models/compute/address.rb create mode 100644 lib/fog/aws/models/compute/addresses.rb create mode 100644 lib/fog/aws/models/compute/dhcp_option.rb create mode 100644 lib/fog/aws/models/compute/dhcp_options.rb create mode 100644 lib/fog/aws/models/compute/flavor.rb create mode 100644 lib/fog/aws/models/compute/flavors.rb create mode 100644 lib/fog/aws/models/compute/image.rb create mode 100644 lib/fog/aws/models/compute/images.rb create mode 100644 lib/fog/aws/models/compute/internet_gateway.rb create mode 100644 lib/fog/aws/models/compute/internet_gateways.rb create mode 100644 lib/fog/aws/models/compute/key_pair.rb create mode 100644 lib/fog/aws/models/compute/key_pairs.rb create mode 100644 lib/fog/aws/models/compute/network_acl.rb create mode 100644 lib/fog/aws/models/compute/network_acls.rb create mode 100644 lib/fog/aws/models/compute/network_interface.rb create mode 100644 lib/fog/aws/models/compute/network_interfaces.rb create mode 100755 lib/fog/aws/models/compute/route_table.rb create mode 100755 lib/fog/aws/models/compute/route_tables.rb create mode 100644 lib/fog/aws/models/compute/security_group.rb create mode 100644 lib/fog/aws/models/compute/security_groups.rb create mode 100644 lib/fog/aws/models/compute/server.rb create mode 100644 lib/fog/aws/models/compute/servers.rb create mode 100644 lib/fog/aws/models/compute/snapshot.rb create mode 100644 lib/fog/aws/models/compute/snapshots.rb create mode 100644 lib/fog/aws/models/compute/spot_request.rb create mode 100644 lib/fog/aws/models/compute/spot_requests.rb create mode 100644 lib/fog/aws/models/compute/subnet.rb create mode 100644 lib/fog/aws/models/compute/subnets.rb create mode 100644 lib/fog/aws/models/compute/tag.rb create mode 100644 lib/fog/aws/models/compute/tags.rb create mode 100644 lib/fog/aws/models/compute/volume.rb create mode 100644 lib/fog/aws/models/compute/volumes.rb create mode 100644 lib/fog/aws/models/compute/vpc.rb create mode 100644 lib/fog/aws/models/compute/vpcs.rb create mode 100644 lib/fog/aws/models/data_pipeline/pipeline.rb create mode 100644 lib/fog/aws/models/data_pipeline/pipelines.rb create mode 100644 lib/fog/aws/models/dns/record.rb create mode 100644 lib/fog/aws/models/dns/records.rb create mode 100644 lib/fog/aws/models/dns/zone.rb create mode 100644 lib/fog/aws/models/dns/zones.rb create mode 100644 lib/fog/aws/models/elasticache/cluster.rb create mode 100644 lib/fog/aws/models/elasticache/clusters.rb create mode 100644 lib/fog/aws/models/elasticache/parameter_group.rb create mode 100644 lib/fog/aws/models/elasticache/parameter_groups.rb create mode 100644 lib/fog/aws/models/elasticache/security_group.rb create mode 100644 lib/fog/aws/models/elasticache/security_groups.rb create mode 100644 lib/fog/aws/models/elasticache/subnet_group.rb create mode 100644 lib/fog/aws/models/elasticache/subnet_groups.rb create mode 100644 lib/fog/aws/models/elb/backend_server_description.rb create mode 100644 lib/fog/aws/models/elb/backend_server_descriptions.rb create mode 100644 lib/fog/aws/models/elb/listener.rb create mode 100644 lib/fog/aws/models/elb/listeners.rb create mode 100644 lib/fog/aws/models/elb/load_balancer.rb create mode 100644 lib/fog/aws/models/elb/load_balancers.rb create mode 100644 lib/fog/aws/models/elb/policies.rb create mode 100644 lib/fog/aws/models/elb/policy.rb create mode 100644 lib/fog/aws/models/glacier/archive.rb create mode 100644 lib/fog/aws/models/glacier/archives.rb create mode 100644 lib/fog/aws/models/glacier/job.rb create mode 100644 lib/fog/aws/models/glacier/jobs.rb create mode 100644 lib/fog/aws/models/glacier/vault.rb create mode 100644 lib/fog/aws/models/glacier/vaults.rb create mode 100644 lib/fog/aws/models/iam/access_key.rb create mode 100644 lib/fog/aws/models/iam/access_keys.rb create mode 100644 lib/fog/aws/models/iam/policies.rb create mode 100644 lib/fog/aws/models/iam/policy.rb create mode 100644 lib/fog/aws/models/iam/role.rb create mode 100644 lib/fog/aws/models/iam/roles.rb create mode 100644 lib/fog/aws/models/iam/user.rb create mode 100644 lib/fog/aws/models/iam/users.rb create mode 100644 lib/fog/aws/models/rds/event_subscription.rb create mode 100644 lib/fog/aws/models/rds/event_subscriptions.rb create mode 100644 lib/fog/aws/models/rds/instance_option.rb create mode 100644 lib/fog/aws/models/rds/instance_options.rb create mode 100644 lib/fog/aws/models/rds/log_file.rb create mode 100644 lib/fog/aws/models/rds/log_files.rb create mode 100644 lib/fog/aws/models/rds/parameter.rb create mode 100644 lib/fog/aws/models/rds/parameter_group.rb create mode 100644 lib/fog/aws/models/rds/parameter_groups.rb create mode 100644 lib/fog/aws/models/rds/parameters.rb create mode 100644 lib/fog/aws/models/rds/security_group.rb create mode 100644 lib/fog/aws/models/rds/security_groups.rb create mode 100644 lib/fog/aws/models/rds/server.rb create mode 100644 lib/fog/aws/models/rds/servers.rb create mode 100644 lib/fog/aws/models/rds/snapshot.rb create mode 100644 lib/fog/aws/models/rds/snapshots.rb create mode 100644 lib/fog/aws/models/rds/subnet_group.rb create mode 100644 lib/fog/aws/models/rds/subnet_groups.rb create mode 100644 lib/fog/aws/models/sns/subscription.rb create mode 100644 lib/fog/aws/models/sns/subscriptions.rb create mode 100644 lib/fog/aws/models/sns/topic.rb create mode 100644 lib/fog/aws/models/sns/topics.rb create mode 100644 lib/fog/aws/models/storage/directories.rb create mode 100644 lib/fog/aws/models/storage/directory.rb create mode 100644 lib/fog/aws/models/storage/file.rb create mode 100644 lib/fog/aws/models/storage/files.rb create mode 100644 lib/fog/aws/models/storage/version.rb create mode 100644 lib/fog/aws/models/storage/versions.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/basic.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_adjustment_types.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_groups.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_instances.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_notification_types.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_launch_configurations.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_metric_collection_types.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_notification_configurations.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_policies.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_scaling_activities.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_scaling_process_types.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_scheduled_actions.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_tags.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/describe_termination_policy_types.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/put_notification_configuration.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/put_scaling_policy.rb create mode 100644 lib/fog/aws/parsers/auto_scaling/terminate_instance_in_auto_scaling_group.rb create mode 100644 lib/fog/aws/parsers/beanstalk/check_dns_availability.rb create mode 100644 lib/fog/aws/parsers/beanstalk/create_application.rb create mode 100644 lib/fog/aws/parsers/beanstalk/create_application_version.rb create mode 100644 lib/fog/aws/parsers/beanstalk/create_configuration_template.rb create mode 100644 lib/fog/aws/parsers/beanstalk/create_environment.rb create mode 100644 lib/fog/aws/parsers/beanstalk/create_storage_location.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_application_versions.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_applications.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_configuration_options.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_configuration_settings.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_environment_resources.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_environments.rb create mode 100644 lib/fog/aws/parsers/beanstalk/describe_events.rb create mode 100644 lib/fog/aws/parsers/beanstalk/empty.rb create mode 100644 lib/fog/aws/parsers/beanstalk/list_available_solution_stacks.rb create mode 100644 lib/fog/aws/parsers/beanstalk/parser.rb create mode 100644 lib/fog/aws/parsers/beanstalk/retrieve_environment_info.rb create mode 100644 lib/fog/aws/parsers/beanstalk/terminate_environment.rb create mode 100644 lib/fog/aws/parsers/beanstalk/update_application.rb create mode 100644 lib/fog/aws/parsers/beanstalk/update_application_version.rb create mode 100644 lib/fog/aws/parsers/beanstalk/update_configuration_template.rb create mode 100644 lib/fog/aws/parsers/beanstalk/update_environment.rb create mode 100644 lib/fog/aws/parsers/beanstalk/validate_configuration_settings.rb create mode 100644 lib/fog/aws/parsers/cdn/distribution.rb create mode 100644 lib/fog/aws/parsers/cdn/get_distribution_list.rb create mode 100644 lib/fog/aws/parsers/cdn/get_invalidation.rb create mode 100644 lib/fog/aws/parsers/cdn/get_invalidation_list.rb create mode 100644 lib/fog/aws/parsers/cdn/get_streaming_distribution_list.rb create mode 100644 lib/fog/aws/parsers/cdn/post_invalidation.rb create mode 100644 lib/fog/aws/parsers/cdn/streaming_distribution.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/basic.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/create_stack.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/describe_stack_events.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/describe_stack_resources.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/describe_stacks.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/get_template.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/list_stack_resources.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/list_stacks.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/update_stack.rb create mode 100644 lib/fog/aws/parsers/cloud_formation/validate_template.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/delete_alarms.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/describe_alarm_history.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/describe_alarms.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/describe_alarms_for_metric.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/disable_alarm_actions.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/enable_alarm_actions.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/get_metric_statistics.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/list_metrics.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/put_metric_alarm.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/put_metric_data.rb create mode 100644 lib/fog/aws/parsers/cloud_watch/set_alarm_state.rb create mode 100644 lib/fog/aws/parsers/compute/allocate_address.rb create mode 100644 lib/fog/aws/parsers/compute/assign_private_ip_addresses.rb create mode 100644 lib/fog/aws/parsers/compute/associate_address.rb create mode 100755 lib/fog/aws/parsers/compute/associate_route_table.rb create mode 100644 lib/fog/aws/parsers/compute/attach_network_interface.rb create mode 100644 lib/fog/aws/parsers/compute/attach_volume.rb create mode 100644 lib/fog/aws/parsers/compute/basic.rb create mode 100644 lib/fog/aws/parsers/compute/cancel_spot_instance_requests.rb create mode 100644 lib/fog/aws/parsers/compute/copy_image.rb create mode 100644 lib/fog/aws/parsers/compute/copy_snapshot.rb create mode 100644 lib/fog/aws/parsers/compute/create_dhcp_options.rb create mode 100644 lib/fog/aws/parsers/compute/create_image.rb create mode 100644 lib/fog/aws/parsers/compute/create_internet_gateway.rb create mode 100644 lib/fog/aws/parsers/compute/create_key_pair.rb create mode 100644 lib/fog/aws/parsers/compute/create_network_acl.rb create mode 100644 lib/fog/aws/parsers/compute/create_network_interface.rb create mode 100755 lib/fog/aws/parsers/compute/create_route_table.rb create mode 100644 lib/fog/aws/parsers/compute/create_security_group.rb create mode 100644 lib/fog/aws/parsers/compute/create_snapshot.rb create mode 100644 lib/fog/aws/parsers/compute/create_subnet.rb create mode 100644 lib/fog/aws/parsers/compute/create_volume.rb create mode 100644 lib/fog/aws/parsers/compute/create_vpc.rb create mode 100644 lib/fog/aws/parsers/compute/deregister_image.rb create mode 100644 lib/fog/aws/parsers/compute/describe_account_attributes.rb create mode 100644 lib/fog/aws/parsers/compute/describe_addresses.rb create mode 100644 lib/fog/aws/parsers/compute/describe_availability_zones.rb create mode 100644 lib/fog/aws/parsers/compute/describe_dhcp_options.rb create mode 100644 lib/fog/aws/parsers/compute/describe_images.rb create mode 100644 lib/fog/aws/parsers/compute/describe_instance_status.rb create mode 100644 lib/fog/aws/parsers/compute/describe_instances.rb create mode 100644 lib/fog/aws/parsers/compute/describe_internet_gateways.rb create mode 100644 lib/fog/aws/parsers/compute/describe_key_pairs.rb create mode 100644 lib/fog/aws/parsers/compute/describe_network_acls.rb create mode 100644 lib/fog/aws/parsers/compute/describe_network_interface_attribute.rb create mode 100644 lib/fog/aws/parsers/compute/describe_network_interfaces.rb create mode 100644 lib/fog/aws/parsers/compute/describe_placement_groups.rb create mode 100644 lib/fog/aws/parsers/compute/describe_regions.rb create mode 100644 lib/fog/aws/parsers/compute/describe_reserved_instances.rb create mode 100644 lib/fog/aws/parsers/compute/describe_reserved_instances_offerings.rb create mode 100755 lib/fog/aws/parsers/compute/describe_route_tables.rb create mode 100644 lib/fog/aws/parsers/compute/describe_security_groups.rb create mode 100644 lib/fog/aws/parsers/compute/describe_snapshots.rb create mode 100644 lib/fog/aws/parsers/compute/describe_spot_price_history.rb create mode 100644 lib/fog/aws/parsers/compute/describe_subnets.rb create mode 100644 lib/fog/aws/parsers/compute/describe_tags.rb create mode 100644 lib/fog/aws/parsers/compute/describe_volume_status.rb create mode 100644 lib/fog/aws/parsers/compute/describe_volumes.rb create mode 100644 lib/fog/aws/parsers/compute/describe_vpc_attribute.rb create mode 100644 lib/fog/aws/parsers/compute/describe_vpcs.rb create mode 100644 lib/fog/aws/parsers/compute/detach_volume.rb create mode 100644 lib/fog/aws/parsers/compute/get_console_output.rb create mode 100644 lib/fog/aws/parsers/compute/get_password_data.rb create mode 100644 lib/fog/aws/parsers/compute/import_key_pair.rb create mode 100644 lib/fog/aws/parsers/compute/modify_subnet_attribute.rb create mode 100644 lib/fog/aws/parsers/compute/monitor_unmonitor_instances.rb create mode 100644 lib/fog/aws/parsers/compute/network_acl_parser.rb create mode 100644 lib/fog/aws/parsers/compute/network_interface_parser.rb create mode 100644 lib/fog/aws/parsers/compute/purchase_reserved_instances_offering.rb create mode 100644 lib/fog/aws/parsers/compute/register_image.rb create mode 100644 lib/fog/aws/parsers/compute/replace_network_acl_association.rb create mode 100644 lib/fog/aws/parsers/compute/run_instances.rb create mode 100644 lib/fog/aws/parsers/compute/spot_datafeed_subscription.rb create mode 100644 lib/fog/aws/parsers/compute/spot_instance_requests.rb create mode 100644 lib/fog/aws/parsers/compute/start_stop_instances.rb create mode 100644 lib/fog/aws/parsers/compute/terminate_instances.rb create mode 100644 lib/fog/aws/parsers/dns/change_resource_record_sets.rb create mode 100644 lib/fog/aws/parsers/dns/create_health_check.rb create mode 100644 lib/fog/aws/parsers/dns/create_hosted_zone.rb create mode 100644 lib/fog/aws/parsers/dns/delete_hosted_zone.rb create mode 100644 lib/fog/aws/parsers/dns/get_change.rb create mode 100644 lib/fog/aws/parsers/dns/get_hosted_zone.rb create mode 100644 lib/fog/aws/parsers/dns/health_check.rb create mode 100644 lib/fog/aws/parsers/dns/list_health_checks.rb create mode 100644 lib/fog/aws/parsers/dns/list_hosted_zones.rb create mode 100644 lib/fog/aws/parsers/dns/list_resource_record_sets.rb create mode 100644 lib/fog/aws/parsers/elasticache/authorize_cache_security_group_ingress.rb create mode 100644 lib/fog/aws/parsers/elasticache/base.rb create mode 100644 lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb create mode 100644 lib/fog/aws/parsers/elasticache/create_cache_subnet_group.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_cache_parameters.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_cache_subnet_groups.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_engine_default_parameters.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_parameter_groups.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_reserved_cache_nodes.rb create mode 100644 lib/fog/aws/parsers/elasticache/describe_security_groups.rb create mode 100644 lib/fog/aws/parsers/elasticache/engine_defaults_parser.rb create mode 100644 lib/fog/aws/parsers/elasticache/event_list.rb create mode 100644 lib/fog/aws/parsers/elasticache/modify_parameter_group.rb create mode 100644 lib/fog/aws/parsers/elasticache/parameter_group_parser.rb create mode 100644 lib/fog/aws/parsers/elasticache/reset_parameter_group.rb create mode 100644 lib/fog/aws/parsers/elasticache/security_group_parser.rb create mode 100644 lib/fog/aws/parsers/elasticache/single_cache_cluster.rb create mode 100644 lib/fog/aws/parsers/elasticache/single_parameter_group.rb create mode 100644 lib/fog/aws/parsers/elasticache/single_security_group.rb create mode 100644 lib/fog/aws/parsers/elasticache/subnet_group_parser.rb create mode 100644 lib/fog/aws/parsers/elb/apply_security_groups_to_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/attach_load_balancer_to_subnets.rb create mode 100644 lib/fog/aws/parsers/elb/configure_health_check.rb create mode 100644 lib/fog/aws/parsers/elb/create_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/delete_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/deregister_instances_from_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/describe_instance_health.rb create mode 100644 lib/fog/aws/parsers/elb/describe_load_balancer_attributes.rb create mode 100644 lib/fog/aws/parsers/elb/describe_load_balancer_policies.rb create mode 100644 lib/fog/aws/parsers/elb/describe_load_balancer_policy_types.rb create mode 100644 lib/fog/aws/parsers/elb/describe_load_balancers.rb create mode 100644 lib/fog/aws/parsers/elb/describe_tags.rb create mode 100644 lib/fog/aws/parsers/elb/detach_load_balancer_from_subnets.rb create mode 100644 lib/fog/aws/parsers/elb/disable_availability_zones_for_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/empty.rb create mode 100644 lib/fog/aws/parsers/elb/enable_availability_zones_for_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/register_instances_with_load_balancer.rb create mode 100644 lib/fog/aws/parsers/elb/tag_list_parser.rb create mode 100644 lib/fog/aws/parsers/emr/add_instance_groups.rb create mode 100644 lib/fog/aws/parsers/emr/add_job_flow_steps.rb create mode 100644 lib/fog/aws/parsers/emr/describe_job_flows.rb create mode 100644 lib/fog/aws/parsers/emr/modify_instance_groups.rb create mode 100644 lib/fog/aws/parsers/emr/run_job_flow.rb create mode 100644 lib/fog/aws/parsers/emr/set_termination_protection.rb create mode 100644 lib/fog/aws/parsers/emr/terminate_job_flows.rb create mode 100644 lib/fog/aws/parsers/iam/base_instance_profile.rb create mode 100644 lib/fog/aws/parsers/iam/basic.rb create mode 100644 lib/fog/aws/parsers/iam/create_access_key.rb create mode 100644 lib/fog/aws/parsers/iam/create_group.rb create mode 100644 lib/fog/aws/parsers/iam/create_user.rb create mode 100644 lib/fog/aws/parsers/iam/get_account_password_policy.rb create mode 100644 lib/fog/aws/parsers/iam/get_account_summary.rb create mode 100644 lib/fog/aws/parsers/iam/get_group.rb create mode 100644 lib/fog/aws/parsers/iam/get_group_policy.rb create mode 100644 lib/fog/aws/parsers/iam/get_role_policy.rb create mode 100644 lib/fog/aws/parsers/iam/get_user.rb create mode 100644 lib/fog/aws/parsers/iam/get_user_policy.rb create mode 100644 lib/fog/aws/parsers/iam/instance_profile.rb create mode 100644 lib/fog/aws/parsers/iam/list_access_keys.rb create mode 100644 lib/fog/aws/parsers/iam/list_account_aliases.rb create mode 100644 lib/fog/aws/parsers/iam/list_groups.rb create mode 100644 lib/fog/aws/parsers/iam/list_groups_for_user.rb create mode 100644 lib/fog/aws/parsers/iam/list_instance_profiles.rb create mode 100644 lib/fog/aws/parsers/iam/list_mfa_devices.rb create mode 100644 lib/fog/aws/parsers/iam/list_policies.rb create mode 100644 lib/fog/aws/parsers/iam/list_roles.rb create mode 100644 lib/fog/aws/parsers/iam/list_server_certificates.rb create mode 100644 lib/fog/aws/parsers/iam/list_signing_certificates.rb create mode 100644 lib/fog/aws/parsers/iam/list_users.rb create mode 100644 lib/fog/aws/parsers/iam/login_profile.rb create mode 100644 lib/fog/aws/parsers/iam/role_parser.rb create mode 100644 lib/fog/aws/parsers/iam/single_role.rb create mode 100644 lib/fog/aws/parsers/iam/update_group.rb create mode 100644 lib/fog/aws/parsers/iam/update_user.rb create mode 100644 lib/fog/aws/parsers/iam/upload_server_certificate.rb create mode 100644 lib/fog/aws/parsers/iam/upload_signing_certificate.rb create mode 100644 lib/fog/aws/parsers/rds/authorize_db_security_group_ingress.rb create mode 100644 lib/fog/aws/parsers/rds/base.rb create mode 100644 lib/fog/aws/parsers/rds/create_db_instance.rb create mode 100644 lib/fog/aws/parsers/rds/create_db_instance_read_replica.rb create mode 100644 lib/fog/aws/parsers/rds/create_db_parameter_group.rb create mode 100644 lib/fog/aws/parsers/rds/create_db_security_group.rb create mode 100644 lib/fog/aws/parsers/rds/create_db_snapshot.rb create mode 100644 lib/fog/aws/parsers/rds/create_db_subnet_group.rb create mode 100644 lib/fog/aws/parsers/rds/create_event_subscription.rb create mode 100644 lib/fog/aws/parsers/rds/db_engine_version_parser.rb create mode 100644 lib/fog/aws/parsers/rds/db_parser.rb create mode 100644 lib/fog/aws/parsers/rds/delete_db_instance.rb create mode 100644 lib/fog/aws/parsers/rds/delete_db_parameter_group.rb create mode 100644 lib/fog/aws/parsers/rds/delete_db_security_group.rb create mode 100644 lib/fog/aws/parsers/rds/delete_db_snapshot.rb create mode 100644 lib/fog/aws/parsers/rds/delete_db_subnet_group.rb create mode 100644 lib/fog/aws/parsers/rds/delete_event_subscription.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_engine_versions.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_instances.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_log_files.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_parameter_groups.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_parameters.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_reserved_instances.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_security_groups.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_snapshots.rb create mode 100644 lib/fog/aws/parsers/rds/describe_db_subnet_groups.rb create mode 100644 lib/fog/aws/parsers/rds/describe_event_subscriptions.rb create mode 100644 lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb create mode 100644 lib/fog/aws/parsers/rds/download_db_logfile_portion.rb create mode 100644 lib/fog/aws/parsers/rds/event_list.rb create mode 100644 lib/fog/aws/parsers/rds/event_subscription_parser.rb create mode 100644 lib/fog/aws/parsers/rds/modify_db_instance.rb create mode 100644 lib/fog/aws/parsers/rds/modify_db_parameter_group.rb create mode 100644 lib/fog/aws/parsers/rds/promote_read_replica.rb create mode 100644 lib/fog/aws/parsers/rds/reboot_db_instance.rb create mode 100644 lib/fog/aws/parsers/rds/restore_db_instance_from_db_snapshot.rb create mode 100644 lib/fog/aws/parsers/rds/restore_db_instance_to_point_in_time.rb create mode 100644 lib/fog/aws/parsers/rds/revoke_db_security_group_ingress.rb create mode 100644 lib/fog/aws/parsers/rds/security_group_parser.rb create mode 100644 lib/fog/aws/parsers/rds/snapshot_parser.rb create mode 100644 lib/fog/aws/parsers/rds/subnet_group_parser.rb create mode 100644 lib/fog/aws/parsers/rds/tag_list_parser.rb create mode 100644 lib/fog/aws/parsers/redshift/cluster.rb create mode 100644 lib/fog/aws/parsers/redshift/cluster_parser.rb create mode 100644 lib/fog/aws/parsers/redshift/cluster_security_group_parser.rb create mode 100644 lib/fog/aws/parsers/redshift/cluster_snapshot.rb create mode 100644 lib/fog/aws/parsers/redshift/cluster_snapshot_parser.rb create mode 100644 lib/fog/aws/parsers/redshift/cluster_subnet_group_parser.rb create mode 100644 lib/fog/aws/parsers/redshift/create_cluster_parameter_group.rb create mode 100644 lib/fog/aws/parsers/redshift/create_cluster_security_group.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_cluster_parameter_groups.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_cluster_parameters.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_cluster_security_groups.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_cluster_snapshots.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_cluster_subnet_groups.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_cluster_versions.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_clusters.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_default_cluster_parameters.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_events.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_orderable_cluster_options.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_reserved_node_offerings.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_reserved_nodes.rb create mode 100644 lib/fog/aws/parsers/redshift/describe_resize.rb create mode 100644 lib/fog/aws/parsers/redshift/purchase_reserved_node_offering.rb create mode 100644 lib/fog/aws/parsers/redshift/revoke_cluster_security_group_ingress.rb create mode 100644 lib/fog/aws/parsers/redshift/update_cluster_parameter_group_parser.rb create mode 100644 lib/fog/aws/parsers/ses/delete_verified_email_address.rb create mode 100644 lib/fog/aws/parsers/ses/get_send_quota.rb create mode 100644 lib/fog/aws/parsers/ses/get_send_statistics.rb create mode 100644 lib/fog/aws/parsers/ses/list_verified_email_addresses.rb create mode 100644 lib/fog/aws/parsers/ses/send_email.rb create mode 100644 lib/fog/aws/parsers/ses/send_raw_email.rb create mode 100644 lib/fog/aws/parsers/ses/verify_domain_identity.rb create mode 100644 lib/fog/aws/parsers/ses/verify_email_address.rb create mode 100644 lib/fog/aws/parsers/simpledb/basic.rb create mode 100644 lib/fog/aws/parsers/simpledb/domain_metadata.rb create mode 100644 lib/fog/aws/parsers/simpledb/get_attributes.rb create mode 100644 lib/fog/aws/parsers/simpledb/list_domains.rb create mode 100644 lib/fog/aws/parsers/simpledb/select.rb create mode 100644 lib/fog/aws/parsers/sns/add_permission.rb create mode 100644 lib/fog/aws/parsers/sns/confirm_subscription.rb create mode 100644 lib/fog/aws/parsers/sns/create_topic.rb create mode 100644 lib/fog/aws/parsers/sns/delete_topic.rb create mode 100644 lib/fog/aws/parsers/sns/get_topic_attributes.rb create mode 100644 lib/fog/aws/parsers/sns/list_subscriptions.rb create mode 100644 lib/fog/aws/parsers/sns/list_topics.rb create mode 100644 lib/fog/aws/parsers/sns/publish.rb create mode 100644 lib/fog/aws/parsers/sns/remove_permission.rb create mode 100644 lib/fog/aws/parsers/sns/set_topic_attributes.rb create mode 100644 lib/fog/aws/parsers/sns/subscribe.rb create mode 100644 lib/fog/aws/parsers/sns/unsubscribe.rb create mode 100644 lib/fog/aws/parsers/sqs/basic.rb create mode 100644 lib/fog/aws/parsers/sqs/create_queue.rb create mode 100644 lib/fog/aws/parsers/sqs/get_queue_attributes.rb create mode 100644 lib/fog/aws/parsers/sqs/list_queues.rb create mode 100644 lib/fog/aws/parsers/sqs/receive_message.rb create mode 100644 lib/fog/aws/parsers/sqs/send_message.rb create mode 100644 lib/fog/aws/parsers/storage/access_control_list.rb create mode 100644 lib/fog/aws/parsers/storage/complete_multipart_upload.rb create mode 100644 lib/fog/aws/parsers/storage/copy_object.rb create mode 100644 lib/fog/aws/parsers/storage/cors_configuration.rb create mode 100644 lib/fog/aws/parsers/storage/delete_multiple_objects.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_location.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_logging.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_object_versions.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_tagging.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_versioning.rb create mode 100644 lib/fog/aws/parsers/storage/get_bucket_website.rb create mode 100644 lib/fog/aws/parsers/storage/get_request_payment.rb create mode 100644 lib/fog/aws/parsers/storage/get_service.rb create mode 100644 lib/fog/aws/parsers/storage/initiate_multipart_upload.rb create mode 100644 lib/fog/aws/parsers/storage/list_multipart_uploads.rb create mode 100644 lib/fog/aws/parsers/storage/list_parts.rb create mode 100644 lib/fog/aws/parsers/sts/assume_role.rb create mode 100644 lib/fog/aws/parsers/sts/assume_role_with_saml.rb create mode 100644 lib/fog/aws/parsers/sts/get_session_token.rb create mode 100644 lib/fog/aws/rds.rb create mode 100644 lib/fog/aws/redshift.rb create mode 100644 lib/fog/aws/region_methods.rb create mode 100644 lib/fog/aws/requests/auto_scaling/create_auto_scaling_group.rb create mode 100644 lib/fog/aws/requests/auto_scaling/create_launch_configuration.rb create mode 100644 lib/fog/aws/requests/auto_scaling/create_or_update_tags.rb create mode 100644 lib/fog/aws/requests/auto_scaling/delete_auto_scaling_group.rb create mode 100644 lib/fog/aws/requests/auto_scaling/delete_launch_configuration.rb create mode 100644 lib/fog/aws/requests/auto_scaling/delete_notification_configuration.rb create mode 100644 lib/fog/aws/requests/auto_scaling/delete_policy.rb create mode 100644 lib/fog/aws/requests/auto_scaling/delete_scheduled_action.rb create mode 100644 lib/fog/aws/requests/auto_scaling/delete_tags.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_adjustment_types.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_auto_scaling_groups.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_auto_scaling_instances.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_auto_scaling_notification_types.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_launch_configurations.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_metric_collection_types.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_notification_configurations.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_policies.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_scaling_activities.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_scaling_process_types.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_scheduled_actions.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_tags.rb create mode 100644 lib/fog/aws/requests/auto_scaling/describe_termination_policy_types.rb create mode 100644 lib/fog/aws/requests/auto_scaling/disable_metrics_collection.rb create mode 100644 lib/fog/aws/requests/auto_scaling/enable_metrics_collection.rb create mode 100644 lib/fog/aws/requests/auto_scaling/execute_policy.rb create mode 100644 lib/fog/aws/requests/auto_scaling/put_notification_configuration.rb create mode 100644 lib/fog/aws/requests/auto_scaling/put_scaling_policy.rb create mode 100644 lib/fog/aws/requests/auto_scaling/put_scheduled_update_group_action.rb create mode 100644 lib/fog/aws/requests/auto_scaling/resume_processes.rb create mode 100644 lib/fog/aws/requests/auto_scaling/set_desired_capacity.rb create mode 100644 lib/fog/aws/requests/auto_scaling/set_instance_health.rb create mode 100644 lib/fog/aws/requests/auto_scaling/suspend_processes.rb create mode 100644 lib/fog/aws/requests/auto_scaling/terminate_instance_in_auto_scaling_group.rb create mode 100644 lib/fog/aws/requests/auto_scaling/update_auto_scaling_group.rb create mode 100644 lib/fog/aws/requests/beanstalk/check_dns_availability.rb create mode 100644 lib/fog/aws/requests/beanstalk/create_application.rb create mode 100644 lib/fog/aws/requests/beanstalk/create_application_version.rb create mode 100644 lib/fog/aws/requests/beanstalk/create_configuration_template.rb create mode 100644 lib/fog/aws/requests/beanstalk/create_environment.rb create mode 100644 lib/fog/aws/requests/beanstalk/create_storage_location.rb create mode 100644 lib/fog/aws/requests/beanstalk/delete_application.rb create mode 100644 lib/fog/aws/requests/beanstalk/delete_application_version.rb create mode 100644 lib/fog/aws/requests/beanstalk/delete_configuration_template.rb create mode 100644 lib/fog/aws/requests/beanstalk/delete_environment_configuration.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_application_versions.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_applications.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_configuration_options.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_configuration_settings.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_environment_resources.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_environments.rb create mode 100644 lib/fog/aws/requests/beanstalk/describe_events.rb create mode 100644 lib/fog/aws/requests/beanstalk/list_available_solution_stacks.rb create mode 100644 lib/fog/aws/requests/beanstalk/rebuild_environment.rb create mode 100644 lib/fog/aws/requests/beanstalk/request_environment_info.rb create mode 100644 lib/fog/aws/requests/beanstalk/restart_app_server.rb create mode 100644 lib/fog/aws/requests/beanstalk/retrieve_environment_info.rb create mode 100644 lib/fog/aws/requests/beanstalk/swap_environment_cnames.rb create mode 100644 lib/fog/aws/requests/beanstalk/terminate_environment.rb create mode 100644 lib/fog/aws/requests/beanstalk/update_application.rb create mode 100644 lib/fog/aws/requests/beanstalk/update_application_version.rb create mode 100644 lib/fog/aws/requests/beanstalk/update_configuration_template.rb create mode 100644 lib/fog/aws/requests/beanstalk/update_environment.rb create mode 100644 lib/fog/aws/requests/beanstalk/validate_configuration_settings.rb create mode 100644 lib/fog/aws/requests/cdn/delete_distribution.rb create mode 100644 lib/fog/aws/requests/cdn/delete_streaming_distribution.rb create mode 100644 lib/fog/aws/requests/cdn/get_distribution.rb create mode 100644 lib/fog/aws/requests/cdn/get_distribution_list.rb create mode 100644 lib/fog/aws/requests/cdn/get_invalidation.rb create mode 100644 lib/fog/aws/requests/cdn/get_invalidation_list.rb create mode 100644 lib/fog/aws/requests/cdn/get_streaming_distribution.rb create mode 100644 lib/fog/aws/requests/cdn/get_streaming_distribution_list.rb create mode 100644 lib/fog/aws/requests/cdn/post_distribution.rb create mode 100644 lib/fog/aws/requests/cdn/post_invalidation.rb create mode 100644 lib/fog/aws/requests/cdn/post_streaming_distribution.rb create mode 100644 lib/fog/aws/requests/cdn/put_distribution_config.rb create mode 100644 lib/fog/aws/requests/cdn/put_streaming_distribution_config.rb create mode 100644 lib/fog/aws/requests/cloud_formation/create_stack.rb create mode 100644 lib/fog/aws/requests/cloud_formation/delete_stack.rb create mode 100644 lib/fog/aws/requests/cloud_formation/describe_stack_events.rb create mode 100644 lib/fog/aws/requests/cloud_formation/describe_stack_resources.rb create mode 100644 lib/fog/aws/requests/cloud_formation/describe_stacks.rb create mode 100644 lib/fog/aws/requests/cloud_formation/get_template.rb create mode 100644 lib/fog/aws/requests/cloud_formation/list_stack_resources.rb create mode 100644 lib/fog/aws/requests/cloud_formation/list_stacks.rb create mode 100644 lib/fog/aws/requests/cloud_formation/update_stack.rb create mode 100644 lib/fog/aws/requests/cloud_formation/validate_template.rb create mode 100644 lib/fog/aws/requests/cloud_watch/delete_alarms.rb create mode 100644 lib/fog/aws/requests/cloud_watch/describe_alarm_history.rb create mode 100644 lib/fog/aws/requests/cloud_watch/describe_alarms.rb create mode 100644 lib/fog/aws/requests/cloud_watch/describe_alarms_for_metric.rb create mode 100644 lib/fog/aws/requests/cloud_watch/disable_alarm_actions.rb create mode 100644 lib/fog/aws/requests/cloud_watch/enable_alarm_actions.rb create mode 100644 lib/fog/aws/requests/cloud_watch/get_metric_statistics.rb create mode 100644 lib/fog/aws/requests/cloud_watch/list_metrics.rb create mode 100644 lib/fog/aws/requests/cloud_watch/put_metric_alarm.rb create mode 100644 lib/fog/aws/requests/cloud_watch/put_metric_data.rb create mode 100644 lib/fog/aws/requests/cloud_watch/set_alarm_state.rb create mode 100644 lib/fog/aws/requests/compute/allocate_address.rb create mode 100644 lib/fog/aws/requests/compute/assign_private_ip_addresses.rb create mode 100644 lib/fog/aws/requests/compute/associate_address.rb create mode 100644 lib/fog/aws/requests/compute/associate_dhcp_options.rb create mode 100755 lib/fog/aws/requests/compute/associate_route_table.rb create mode 100644 lib/fog/aws/requests/compute/attach_internet_gateway.rb create mode 100644 lib/fog/aws/requests/compute/attach_network_interface.rb create mode 100644 lib/fog/aws/requests/compute/attach_volume.rb create mode 100644 lib/fog/aws/requests/compute/authorize_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb create mode 100644 lib/fog/aws/requests/compute/copy_image.rb create mode 100644 lib/fog/aws/requests/compute/copy_snapshot.rb create mode 100644 lib/fog/aws/requests/compute/create_dhcp_options.rb create mode 100644 lib/fog/aws/requests/compute/create_image.rb create mode 100644 lib/fog/aws/requests/compute/create_internet_gateway.rb create mode 100644 lib/fog/aws/requests/compute/create_key_pair.rb create mode 100644 lib/fog/aws/requests/compute/create_network_acl.rb create mode 100644 lib/fog/aws/requests/compute/create_network_acl_entry.rb create mode 100644 lib/fog/aws/requests/compute/create_network_interface.rb create mode 100644 lib/fog/aws/requests/compute/create_placement_group.rb create mode 100755 lib/fog/aws/requests/compute/create_route.rb create mode 100755 lib/fog/aws/requests/compute/create_route_table.rb create mode 100644 lib/fog/aws/requests/compute/create_security_group.rb create mode 100644 lib/fog/aws/requests/compute/create_snapshot.rb create mode 100644 lib/fog/aws/requests/compute/create_spot_datafeed_subscription.rb create mode 100644 lib/fog/aws/requests/compute/create_subnet.rb create mode 100644 lib/fog/aws/requests/compute/create_tags.rb create mode 100644 lib/fog/aws/requests/compute/create_volume.rb create mode 100644 lib/fog/aws/requests/compute/create_vpc.rb create mode 100644 lib/fog/aws/requests/compute/delete_dhcp_options.rb create mode 100644 lib/fog/aws/requests/compute/delete_internet_gateway.rb create mode 100644 lib/fog/aws/requests/compute/delete_key_pair.rb create mode 100644 lib/fog/aws/requests/compute/delete_network_acl.rb create mode 100644 lib/fog/aws/requests/compute/delete_network_acl_entry.rb create mode 100644 lib/fog/aws/requests/compute/delete_network_interface.rb create mode 100644 lib/fog/aws/requests/compute/delete_placement_group.rb create mode 100755 lib/fog/aws/requests/compute/delete_route.rb create mode 100755 lib/fog/aws/requests/compute/delete_route_table.rb create mode 100644 lib/fog/aws/requests/compute/delete_security_group.rb create mode 100644 lib/fog/aws/requests/compute/delete_snapshot.rb create mode 100644 lib/fog/aws/requests/compute/delete_spot_datafeed_subscription.rb create mode 100644 lib/fog/aws/requests/compute/delete_subnet.rb create mode 100644 lib/fog/aws/requests/compute/delete_tags.rb create mode 100644 lib/fog/aws/requests/compute/delete_volume.rb create mode 100644 lib/fog/aws/requests/compute/delete_vpc.rb create mode 100644 lib/fog/aws/requests/compute/deregister_image.rb create mode 100644 lib/fog/aws/requests/compute/describe_account_attributes.rb create mode 100644 lib/fog/aws/requests/compute/describe_addresses.rb create mode 100644 lib/fog/aws/requests/compute/describe_availability_zones.rb create mode 100644 lib/fog/aws/requests/compute/describe_dhcp_options.rb create mode 100644 lib/fog/aws/requests/compute/describe_images.rb create mode 100644 lib/fog/aws/requests/compute/describe_instance_status.rb create mode 100644 lib/fog/aws/requests/compute/describe_instances.rb create mode 100644 lib/fog/aws/requests/compute/describe_internet_gateways.rb create mode 100644 lib/fog/aws/requests/compute/describe_key_pairs.rb create mode 100644 lib/fog/aws/requests/compute/describe_network_acls.rb create mode 100644 lib/fog/aws/requests/compute/describe_network_interface_attribute.rb create mode 100644 lib/fog/aws/requests/compute/describe_network_interfaces.rb create mode 100644 lib/fog/aws/requests/compute/describe_placement_groups.rb create mode 100644 lib/fog/aws/requests/compute/describe_regions.rb create mode 100644 lib/fog/aws/requests/compute/describe_reserved_instances.rb create mode 100644 lib/fog/aws/requests/compute/describe_reserved_instances_offerings.rb create mode 100755 lib/fog/aws/requests/compute/describe_route_tables.rb create mode 100644 lib/fog/aws/requests/compute/describe_security_groups.rb create mode 100644 lib/fog/aws/requests/compute/describe_snapshots.rb create mode 100644 lib/fog/aws/requests/compute/describe_spot_datafeed_subscription.rb create mode 100644 lib/fog/aws/requests/compute/describe_spot_instance_requests.rb create mode 100644 lib/fog/aws/requests/compute/describe_spot_price_history.rb create mode 100644 lib/fog/aws/requests/compute/describe_subnets.rb create mode 100644 lib/fog/aws/requests/compute/describe_tags.rb create mode 100644 lib/fog/aws/requests/compute/describe_volume_status.rb create mode 100644 lib/fog/aws/requests/compute/describe_volumes.rb create mode 100644 lib/fog/aws/requests/compute/describe_vpc_attribute.rb create mode 100644 lib/fog/aws/requests/compute/describe_vpcs.rb create mode 100644 lib/fog/aws/requests/compute/detach_internet_gateway.rb create mode 100644 lib/fog/aws/requests/compute/detach_network_interface.rb create mode 100644 lib/fog/aws/requests/compute/detach_volume.rb create mode 100644 lib/fog/aws/requests/compute/disassociate_address.rb create mode 100755 lib/fog/aws/requests/compute/disassociate_route_table.rb create mode 100644 lib/fog/aws/requests/compute/get_console_output.rb create mode 100644 lib/fog/aws/requests/compute/get_password_data.rb create mode 100644 lib/fog/aws/requests/compute/import_key_pair.rb create mode 100644 lib/fog/aws/requests/compute/modify_image_attribute.rb create mode 100644 lib/fog/aws/requests/compute/modify_instance_attribute.rb create mode 100644 lib/fog/aws/requests/compute/modify_network_interface_attribute.rb create mode 100644 lib/fog/aws/requests/compute/modify_snapshot_attribute.rb create mode 100644 lib/fog/aws/requests/compute/modify_subnet_attribute.rb create mode 100644 lib/fog/aws/requests/compute/modify_volume_attribute.rb create mode 100644 lib/fog/aws/requests/compute/modify_vpc_attribute.rb create mode 100644 lib/fog/aws/requests/compute/monitor_instances.rb create mode 100644 lib/fog/aws/requests/compute/purchase_reserved_instances_offering.rb create mode 100644 lib/fog/aws/requests/compute/reboot_instances.rb create mode 100644 lib/fog/aws/requests/compute/register_image.rb create mode 100644 lib/fog/aws/requests/compute/release_address.rb create mode 100644 lib/fog/aws/requests/compute/replace_network_acl_association.rb create mode 100644 lib/fog/aws/requests/compute/replace_network_acl_entry.rb create mode 100755 lib/fog/aws/requests/compute/replace_route.rb create mode 100644 lib/fog/aws/requests/compute/request_spot_instances.rb create mode 100644 lib/fog/aws/requests/compute/reset_network_interface_attribute.rb create mode 100644 lib/fog/aws/requests/compute/revoke_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/compute/run_instances.rb create mode 100644 lib/fog/aws/requests/compute/start_instances.rb create mode 100644 lib/fog/aws/requests/compute/stop_instances.rb create mode 100644 lib/fog/aws/requests/compute/terminate_instances.rb create mode 100644 lib/fog/aws/requests/compute/unmonitor_instances.rb create mode 100644 lib/fog/aws/requests/data_pipeline/activate_pipeline.rb create mode 100644 lib/fog/aws/requests/data_pipeline/create_pipeline.rb create mode 100644 lib/fog/aws/requests/data_pipeline/delete_pipeline.rb create mode 100644 lib/fog/aws/requests/data_pipeline/describe_objects.rb create mode 100644 lib/fog/aws/requests/data_pipeline/describe_pipelines.rb create mode 100644 lib/fog/aws/requests/data_pipeline/get_pipeline_definition.rb create mode 100644 lib/fog/aws/requests/data_pipeline/list_pipelines.rb create mode 100644 lib/fog/aws/requests/data_pipeline/put_pipeline_definition.rb create mode 100644 lib/fog/aws/requests/data_pipeline/query_objects.rb create mode 100644 lib/fog/aws/requests/dns/change_resource_record_sets.rb create mode 100644 lib/fog/aws/requests/dns/create_health_check.rb create mode 100644 lib/fog/aws/requests/dns/create_hosted_zone.rb create mode 100644 lib/fog/aws/requests/dns/delete_health_check.rb create mode 100644 lib/fog/aws/requests/dns/delete_hosted_zone.rb create mode 100644 lib/fog/aws/requests/dns/get_change.rb create mode 100644 lib/fog/aws/requests/dns/get_health_check.rb create mode 100644 lib/fog/aws/requests/dns/get_hosted_zone.rb create mode 100644 lib/fog/aws/requests/dns/list_health_checks.rb create mode 100644 lib/fog/aws/requests/dns/list_hosted_zones.rb create mode 100644 lib/fog/aws/requests/dns/list_resource_record_sets.rb create mode 100644 lib/fog/aws/requests/dynamodb/batch_get_item.rb create mode 100644 lib/fog/aws/requests/dynamodb/batch_write_item.rb create mode 100644 lib/fog/aws/requests/dynamodb/create_table.rb create mode 100644 lib/fog/aws/requests/dynamodb/delete_item.rb create mode 100644 lib/fog/aws/requests/dynamodb/delete_table.rb create mode 100644 lib/fog/aws/requests/dynamodb/describe_table.rb create mode 100644 lib/fog/aws/requests/dynamodb/get_item.rb create mode 100644 lib/fog/aws/requests/dynamodb/list_tables.rb create mode 100644 lib/fog/aws/requests/dynamodb/put_item.rb create mode 100644 lib/fog/aws/requests/dynamodb/query.rb create mode 100644 lib/fog/aws/requests/dynamodb/scan.rb create mode 100644 lib/fog/aws/requests/dynamodb/update_item.rb create mode 100644 lib/fog/aws/requests/dynamodb/update_table.rb create mode 100644 lib/fog/aws/requests/elasticache/authorize_cache_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/elasticache/create_cache_cluster.rb create mode 100644 lib/fog/aws/requests/elasticache/create_cache_parameter_group.rb create mode 100644 lib/fog/aws/requests/elasticache/create_cache_security_group.rb create mode 100644 lib/fog/aws/requests/elasticache/create_cache_subnet_group.rb create mode 100644 lib/fog/aws/requests/elasticache/delete_cache_cluster.rb create mode 100644 lib/fog/aws/requests/elasticache/delete_cache_parameter_group.rb create mode 100644 lib/fog/aws/requests/elasticache/delete_cache_security_group.rb create mode 100644 lib/fog/aws/requests/elasticache/delete_cache_subnet_group.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_cache_clusters.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_cache_parameter_groups.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_cache_parameters.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_cache_security_groups.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_cache_subnet_groups.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_engine_default_parameters.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_events.rb create mode 100644 lib/fog/aws/requests/elasticache/describe_reserved_cache_nodes.rb create mode 100644 lib/fog/aws/requests/elasticache/modify_cache_cluster.rb create mode 100644 lib/fog/aws/requests/elasticache/modify_cache_parameter_group.rb create mode 100644 lib/fog/aws/requests/elasticache/reboot_cache_cluster.rb create mode 100644 lib/fog/aws/requests/elasticache/reset_cache_parameter_group.rb create mode 100644 lib/fog/aws/requests/elasticache/revoke_cache_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/elb/add_tags.rb create mode 100644 lib/fog/aws/requests/elb/apply_security_groups_to_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/attach_load_balancer_to_subnets.rb create mode 100644 lib/fog/aws/requests/elb/configure_health_check.rb create mode 100644 lib/fog/aws/requests/elb/create_app_cookie_stickiness_policy.rb create mode 100644 lib/fog/aws/requests/elb/create_lb_cookie_stickiness_policy.rb create mode 100644 lib/fog/aws/requests/elb/create_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/create_load_balancer_listeners.rb create mode 100644 lib/fog/aws/requests/elb/create_load_balancer_policy.rb create mode 100644 lib/fog/aws/requests/elb/delete_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/delete_load_balancer_listeners.rb create mode 100644 lib/fog/aws/requests/elb/delete_load_balancer_policy.rb create mode 100644 lib/fog/aws/requests/elb/deregister_instances_from_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/describe_instance_health.rb create mode 100644 lib/fog/aws/requests/elb/describe_load_balancer_attributes.rb create mode 100644 lib/fog/aws/requests/elb/describe_load_balancer_policies.rb create mode 100644 lib/fog/aws/requests/elb/describe_load_balancer_policy_types.rb create mode 100644 lib/fog/aws/requests/elb/describe_load_balancers.rb create mode 100644 lib/fog/aws/requests/elb/describe_tags.rb create mode 100644 lib/fog/aws/requests/elb/detach_load_balancer_from_subnets.rb create mode 100644 lib/fog/aws/requests/elb/disable_availability_zones_for_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/enable_availability_zones_for_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/modify_load_balancer_attributes.rb create mode 100644 lib/fog/aws/requests/elb/register_instances_with_load_balancer.rb create mode 100644 lib/fog/aws/requests/elb/remove_tags.rb create mode 100644 lib/fog/aws/requests/elb/set_load_balancer_listener_ssl_certificate.rb create mode 100644 lib/fog/aws/requests/elb/set_load_balancer_policies_for_backend_server.rb create mode 100644 lib/fog/aws/requests/elb/set_load_balancer_policies_of_listener.rb create mode 100644 lib/fog/aws/requests/emr/add_instance_groups.rb create mode 100644 lib/fog/aws/requests/emr/add_job_flow_steps.rb create mode 100644 lib/fog/aws/requests/emr/describe_job_flows.rb create mode 100644 lib/fog/aws/requests/emr/modify_instance_groups.rb create mode 100644 lib/fog/aws/requests/emr/run_job_flow.rb create mode 100644 lib/fog/aws/requests/emr/set_termination_protection.rb create mode 100644 lib/fog/aws/requests/emr/terminate_job_flows.rb create mode 100644 lib/fog/aws/requests/glacier/abort_multipart_upload.rb create mode 100644 lib/fog/aws/requests/glacier/complete_multipart_upload.rb create mode 100644 lib/fog/aws/requests/glacier/create_archive.rb create mode 100644 lib/fog/aws/requests/glacier/create_vault.rb create mode 100644 lib/fog/aws/requests/glacier/delete_archive.rb create mode 100644 lib/fog/aws/requests/glacier/delete_vault.rb create mode 100644 lib/fog/aws/requests/glacier/delete_vault_notification_configuration.rb create mode 100644 lib/fog/aws/requests/glacier/describe_job.rb create mode 100644 lib/fog/aws/requests/glacier/describe_vault.rb create mode 100644 lib/fog/aws/requests/glacier/get_job_output.rb create mode 100644 lib/fog/aws/requests/glacier/get_vault_notification_configuration.rb create mode 100644 lib/fog/aws/requests/glacier/initiate_job.rb create mode 100644 lib/fog/aws/requests/glacier/initiate_multipart_upload.rb create mode 100644 lib/fog/aws/requests/glacier/list_jobs.rb create mode 100644 lib/fog/aws/requests/glacier/list_multipart_uploads.rb create mode 100644 lib/fog/aws/requests/glacier/list_parts.rb create mode 100644 lib/fog/aws/requests/glacier/list_vaults.rb create mode 100644 lib/fog/aws/requests/glacier/set_vault_notification_configuration.rb create mode 100644 lib/fog/aws/requests/glacier/upload_part.rb create mode 100644 lib/fog/aws/requests/iam/add_role_to_instance_profile.rb create mode 100644 lib/fog/aws/requests/iam/add_user_to_group.rb create mode 100644 lib/fog/aws/requests/iam/create_access_key.rb create mode 100644 lib/fog/aws/requests/iam/create_account_alias.rb create mode 100644 lib/fog/aws/requests/iam/create_group.rb create mode 100644 lib/fog/aws/requests/iam/create_instance_profile.rb create mode 100644 lib/fog/aws/requests/iam/create_login_profile.rb create mode 100644 lib/fog/aws/requests/iam/create_role.rb create mode 100644 lib/fog/aws/requests/iam/create_user.rb create mode 100644 lib/fog/aws/requests/iam/delete_access_key.rb create mode 100644 lib/fog/aws/requests/iam/delete_account_alias.rb create mode 100644 lib/fog/aws/requests/iam/delete_account_password_policy.rb create mode 100644 lib/fog/aws/requests/iam/delete_group.rb create mode 100644 lib/fog/aws/requests/iam/delete_group_policy.rb create mode 100644 lib/fog/aws/requests/iam/delete_instance_profile.rb create mode 100644 lib/fog/aws/requests/iam/delete_login_profile.rb create mode 100644 lib/fog/aws/requests/iam/delete_role.rb create mode 100644 lib/fog/aws/requests/iam/delete_role_policy.rb create mode 100644 lib/fog/aws/requests/iam/delete_server_certificate.rb create mode 100644 lib/fog/aws/requests/iam/delete_signing_certificate.rb create mode 100644 lib/fog/aws/requests/iam/delete_user.rb create mode 100644 lib/fog/aws/requests/iam/delete_user_policy.rb create mode 100644 lib/fog/aws/requests/iam/get_account_password_policy.rb create mode 100644 lib/fog/aws/requests/iam/get_account_summary.rb create mode 100644 lib/fog/aws/requests/iam/get_group.rb create mode 100644 lib/fog/aws/requests/iam/get_group_policy.rb create mode 100644 lib/fog/aws/requests/iam/get_instance_profile.rb create mode 100644 lib/fog/aws/requests/iam/get_login_profile.rb create mode 100644 lib/fog/aws/requests/iam/get_role.rb create mode 100644 lib/fog/aws/requests/iam/get_role_policy.rb create mode 100644 lib/fog/aws/requests/iam/get_server_certificate.rb create mode 100644 lib/fog/aws/requests/iam/get_user.rb create mode 100644 lib/fog/aws/requests/iam/get_user_policy.rb create mode 100644 lib/fog/aws/requests/iam/list_access_keys.rb create mode 100644 lib/fog/aws/requests/iam/list_account_aliases.rb create mode 100644 lib/fog/aws/requests/iam/list_group_policies.rb create mode 100644 lib/fog/aws/requests/iam/list_groups.rb create mode 100644 lib/fog/aws/requests/iam/list_groups_for_user.rb create mode 100644 lib/fog/aws/requests/iam/list_instance_profiles.rb create mode 100644 lib/fog/aws/requests/iam/list_instance_profiles_for_role.rb create mode 100644 lib/fog/aws/requests/iam/list_mfa_devices.rb create mode 100644 lib/fog/aws/requests/iam/list_role_policies.rb create mode 100644 lib/fog/aws/requests/iam/list_roles.rb create mode 100644 lib/fog/aws/requests/iam/list_server_certificates.rb create mode 100644 lib/fog/aws/requests/iam/list_signing_certificates.rb create mode 100644 lib/fog/aws/requests/iam/list_user_policies.rb create mode 100644 lib/fog/aws/requests/iam/list_users.rb create mode 100644 lib/fog/aws/requests/iam/put_group_policy.rb create mode 100644 lib/fog/aws/requests/iam/put_role_policy.rb create mode 100644 lib/fog/aws/requests/iam/put_user_policy.rb create mode 100644 lib/fog/aws/requests/iam/remove_role_from_instance_profile.rb create mode 100644 lib/fog/aws/requests/iam/remove_user_from_group.rb create mode 100644 lib/fog/aws/requests/iam/update_access_key.rb create mode 100644 lib/fog/aws/requests/iam/update_account_password_policy.rb create mode 100644 lib/fog/aws/requests/iam/update_group.rb create mode 100644 lib/fog/aws/requests/iam/update_login_profile.rb create mode 100644 lib/fog/aws/requests/iam/update_server_certificate.rb create mode 100644 lib/fog/aws/requests/iam/update_signing_certificate.rb create mode 100644 lib/fog/aws/requests/iam/update_user.rb create mode 100644 lib/fog/aws/requests/iam/upload_server_certificate.rb create mode 100644 lib/fog/aws/requests/iam/upload_signing_certificate.rb create mode 100644 lib/fog/aws/requests/rds/add_tags_to_resource.rb create mode 100644 lib/fog/aws/requests/rds/authorize_db_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/rds/create_db_instance.rb create mode 100644 lib/fog/aws/requests/rds/create_db_instance_read_replica.rb create mode 100644 lib/fog/aws/requests/rds/create_db_parameter_group.rb create mode 100644 lib/fog/aws/requests/rds/create_db_security_group.rb create mode 100644 lib/fog/aws/requests/rds/create_db_snapshot.rb create mode 100644 lib/fog/aws/requests/rds/create_db_subnet_group.rb create mode 100644 lib/fog/aws/requests/rds/create_event_subscription.rb create mode 100644 lib/fog/aws/requests/rds/delete_db_instance.rb create mode 100644 lib/fog/aws/requests/rds/delete_db_parameter_group.rb create mode 100644 lib/fog/aws/requests/rds/delete_db_security_group.rb create mode 100644 lib/fog/aws/requests/rds/delete_db_snapshot.rb create mode 100644 lib/fog/aws/requests/rds/delete_db_subnet_group.rb create mode 100644 lib/fog/aws/requests/rds/delete_event_subscription.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_engine_versions.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_instances.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_log_files.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_parameter_groups.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_parameters.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_reserved_instances.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_security_groups.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_snapshots.rb create mode 100644 lib/fog/aws/requests/rds/describe_db_subnet_groups.rb create mode 100644 lib/fog/aws/requests/rds/describe_event_subscriptions.rb create mode 100644 lib/fog/aws/requests/rds/describe_events.rb create mode 100644 lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb create mode 100644 lib/fog/aws/requests/rds/download_db_logfile_portion.rb create mode 100644 lib/fog/aws/requests/rds/list_tags_for_resource.rb create mode 100644 lib/fog/aws/requests/rds/modify_db_instance.rb create mode 100644 lib/fog/aws/requests/rds/modify_db_parameter_group.rb create mode 100644 lib/fog/aws/requests/rds/promote_read_replica.rb create mode 100644 lib/fog/aws/requests/rds/reboot_db_instance.rb create mode 100644 lib/fog/aws/requests/rds/remove_tags_from_resource.rb create mode 100644 lib/fog/aws/requests/rds/restore_db_instance_from_db_snapshot.rb create mode 100644 lib/fog/aws/requests/rds/restore_db_instance_to_point_in_time.rb create mode 100644 lib/fog/aws/requests/rds/revoke_db_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/redshift/authorize_cluster_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/redshift/authorize_snapshot_access.rb create mode 100644 lib/fog/aws/requests/redshift/copy_cluster_snapshot.rb create mode 100644 lib/fog/aws/requests/redshift/create_cluster.rb create mode 100644 lib/fog/aws/requests/redshift/create_cluster_parameter_group.rb create mode 100644 lib/fog/aws/requests/redshift/create_cluster_security_group.rb create mode 100644 lib/fog/aws/requests/redshift/create_cluster_snapshot.rb create mode 100644 lib/fog/aws/requests/redshift/create_cluster_subnet_group.rb create mode 100644 lib/fog/aws/requests/redshift/delete_cluster.rb create mode 100644 lib/fog/aws/requests/redshift/delete_cluster_parameter_group.rb create mode 100644 lib/fog/aws/requests/redshift/delete_cluster_security_group.rb create mode 100644 lib/fog/aws/requests/redshift/delete_cluster_snapshot.rb create mode 100644 lib/fog/aws/requests/redshift/delete_cluster_subnet_group.rb create mode 100644 lib/fog/aws/requests/redshift/describe_cluster_parameter_groups.rb create mode 100644 lib/fog/aws/requests/redshift/describe_cluster_parameters.rb create mode 100644 lib/fog/aws/requests/redshift/describe_cluster_security_groups.rb create mode 100644 lib/fog/aws/requests/redshift/describe_cluster_snapshots.rb create mode 100644 lib/fog/aws/requests/redshift/describe_cluster_subnet_groups.rb create mode 100644 lib/fog/aws/requests/redshift/describe_cluster_versions.rb create mode 100644 lib/fog/aws/requests/redshift/describe_clusters.rb create mode 100644 lib/fog/aws/requests/redshift/describe_default_cluster_parameters.rb create mode 100644 lib/fog/aws/requests/redshift/describe_events.rb create mode 100644 lib/fog/aws/requests/redshift/describe_orderable_cluster_options.rb create mode 100644 lib/fog/aws/requests/redshift/describe_reserved_node_offerings.rb create mode 100644 lib/fog/aws/requests/redshift/describe_reserved_nodes.rb create mode 100644 lib/fog/aws/requests/redshift/describe_resize.rb create mode 100644 lib/fog/aws/requests/redshift/modify_cluster.rb create mode 100644 lib/fog/aws/requests/redshift/modify_cluster_parameter_group.rb create mode 100644 lib/fog/aws/requests/redshift/modify_cluster_subnet_group.rb create mode 100644 lib/fog/aws/requests/redshift/purchase_reserved_node_offering.rb create mode 100644 lib/fog/aws/requests/redshift/reboot_cluster.rb create mode 100644 lib/fog/aws/requests/redshift/reset_cluster_parameter_group.rb create mode 100644 lib/fog/aws/requests/redshift/restore_from_cluster_snapshot.rb create mode 100644 lib/fog/aws/requests/redshift/revoke_cluster_security_group_ingress.rb create mode 100644 lib/fog/aws/requests/redshift/revoke_snapshot_access.rb create mode 100644 lib/fog/aws/requests/ses/delete_verified_email_address.rb create mode 100644 lib/fog/aws/requests/ses/get_send_quota.rb create mode 100644 lib/fog/aws/requests/ses/get_send_statistics.rb create mode 100644 lib/fog/aws/requests/ses/list_verified_email_addresses.rb create mode 100644 lib/fog/aws/requests/ses/send_email.rb create mode 100644 lib/fog/aws/requests/ses/send_raw_email.rb create mode 100644 lib/fog/aws/requests/ses/verify_domain_identity.rb create mode 100644 lib/fog/aws/requests/ses/verify_email_address.rb create mode 100644 lib/fog/aws/requests/simpledb/batch_put_attributes.rb create mode 100644 lib/fog/aws/requests/simpledb/create_domain.rb create mode 100644 lib/fog/aws/requests/simpledb/delete_attributes.rb create mode 100644 lib/fog/aws/requests/simpledb/delete_domain.rb create mode 100644 lib/fog/aws/requests/simpledb/domain_metadata.rb create mode 100644 lib/fog/aws/requests/simpledb/get_attributes.rb create mode 100644 lib/fog/aws/requests/simpledb/list_domains.rb create mode 100644 lib/fog/aws/requests/simpledb/put_attributes.rb create mode 100644 lib/fog/aws/requests/simpledb/select.rb create mode 100644 lib/fog/aws/requests/sns/add_permission.rb create mode 100644 lib/fog/aws/requests/sns/confirm_subscription.rb create mode 100644 lib/fog/aws/requests/sns/create_topic.rb create mode 100644 lib/fog/aws/requests/sns/delete_topic.rb create mode 100644 lib/fog/aws/requests/sns/get_topic_attributes.rb create mode 100644 lib/fog/aws/requests/sns/list_subscriptions.rb create mode 100644 lib/fog/aws/requests/sns/list_subscriptions_by_topic.rb create mode 100644 lib/fog/aws/requests/sns/list_topics.rb create mode 100644 lib/fog/aws/requests/sns/publish.rb create mode 100644 lib/fog/aws/requests/sns/remove_permission.rb create mode 100644 lib/fog/aws/requests/sns/set_topic_attributes.rb create mode 100644 lib/fog/aws/requests/sns/subscribe.rb create mode 100644 lib/fog/aws/requests/sns/unsubscribe.rb create mode 100644 lib/fog/aws/requests/sqs/change_message_visibility.rb create mode 100644 lib/fog/aws/requests/sqs/create_queue.rb create mode 100644 lib/fog/aws/requests/sqs/delete_message.rb create mode 100644 lib/fog/aws/requests/sqs/delete_queue.rb create mode 100644 lib/fog/aws/requests/sqs/get_queue_attributes.rb create mode 100644 lib/fog/aws/requests/sqs/list_queues.rb create mode 100644 lib/fog/aws/requests/sqs/receive_message.rb create mode 100644 lib/fog/aws/requests/sqs/send_message.rb create mode 100644 lib/fog/aws/requests/sqs/set_queue_attributes.rb create mode 100644 lib/fog/aws/requests/storage/abort_multipart_upload.rb create mode 100644 lib/fog/aws/requests/storage/acl_utils.rb create mode 100644 lib/fog/aws/requests/storage/complete_multipart_upload.rb create mode 100644 lib/fog/aws/requests/storage/copy_object.rb create mode 100644 lib/fog/aws/requests/storage/cors_utils.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket_cors.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket_policy.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket_tagging.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket_website.rb create mode 100644 lib/fog/aws/requests/storage/delete_multiple_objects.rb create mode 100644 lib/fog/aws/requests/storage/delete_object.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_acl.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_cors.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_lifecycle.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_location.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_logging.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_object_versions.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_policy.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_tagging.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_versioning.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_website.rb create mode 100644 lib/fog/aws/requests/storage/get_object.rb create mode 100644 lib/fog/aws/requests/storage/get_object_acl.rb create mode 100644 lib/fog/aws/requests/storage/get_object_http_url.rb create mode 100644 lib/fog/aws/requests/storage/get_object_https_url.rb create mode 100644 lib/fog/aws/requests/storage/get_object_torrent.rb create mode 100644 lib/fog/aws/requests/storage/get_object_url.rb create mode 100644 lib/fog/aws/requests/storage/get_request_payment.rb create mode 100644 lib/fog/aws/requests/storage/get_service.rb create mode 100644 lib/fog/aws/requests/storage/head_bucket.rb create mode 100644 lib/fog/aws/requests/storage/head_object.rb create mode 100644 lib/fog/aws/requests/storage/initiate_multipart_upload.rb create mode 100644 lib/fog/aws/requests/storage/list_multipart_uploads.rb create mode 100644 lib/fog/aws/requests/storage/list_parts.rb create mode 100644 lib/fog/aws/requests/storage/post_object_hidden_fields.rb create mode 100644 lib/fog/aws/requests/storage/post_object_restore.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_acl.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_cors.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_lifecycle.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_logging.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_policy.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_tagging.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_versioning.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_website.rb create mode 100644 lib/fog/aws/requests/storage/put_object.rb create mode 100644 lib/fog/aws/requests/storage/put_object_acl.rb create mode 100644 lib/fog/aws/requests/storage/put_object_url.rb create mode 100644 lib/fog/aws/requests/storage/put_request_payment.rb create mode 100644 lib/fog/aws/requests/storage/shared_mock_methods.rb create mode 100644 lib/fog/aws/requests/storage/sync_clock.rb create mode 100644 lib/fog/aws/requests/storage/upload_part.rb create mode 100644 lib/fog/aws/requests/sts/assume_role.rb create mode 100644 lib/fog/aws/requests/sts/assume_role_with_saml.rb create mode 100644 lib/fog/aws/requests/sts/get_federation_token.rb create mode 100644 lib/fog/aws/requests/sts/get_session_token.rb create mode 100644 lib/fog/aws/ses.rb create mode 100644 lib/fog/aws/signaturev4.rb create mode 100644 lib/fog/aws/simpledb.rb create mode 100644 lib/fog/aws/sns.rb create mode 100644 lib/fog/aws/sqs.rb create mode 100644 lib/fog/aws/storage.rb create mode 100644 lib/fog/aws/sts.rb create mode 100644 tests/credentials_tests.rb create mode 100644 tests/helper.rb create mode 100644 tests/helpers/collection_helper.rb create mode 100644 tests/helpers/compute/flavors_helper.rb create mode 100644 tests/helpers/compute/server_helper.rb create mode 100644 tests/helpers/compute/servers_helper.rb create mode 100644 tests/helpers/dns_helper.rb create mode 100644 tests/helpers/formats_helper.rb create mode 100644 tests/helpers/formats_helper_tests.rb create mode 100644 tests/helpers/mock_helper.rb create mode 100644 tests/helpers/model_helper.rb create mode 100644 tests/helpers/responds_to_helper.rb create mode 100644 tests/helpers/schema_validator_tests.rb create mode 100644 tests/helpers/succeeds_helper.rb create mode 100644 tests/models/auto_scaling/activities_tests.rb create mode 100644 tests/models/auto_scaling/configuration_test.rb create mode 100644 tests/models/auto_scaling/configurations_tests.rb create mode 100644 tests/models/auto_scaling/groups_test.rb create mode 100644 tests/models/auto_scaling/helper.rb create mode 100644 tests/models/auto_scaling/instance_tests.rb create mode 100644 tests/models/auto_scaling/instances_tests.rb create mode 100644 tests/models/beanstalk/application_tests.rb create mode 100644 tests/models/beanstalk/applications_tests.rb create mode 100644 tests/models/beanstalk/environment_tests.rb create mode 100644 tests/models/beanstalk/environments_tests.rb create mode 100644 tests/models/beanstalk/template_tests.rb create mode 100644 tests/models/beanstalk/templates_tests.rb create mode 100644 tests/models/beanstalk/version_tests.rb create mode 100644 tests/models/beanstalk/versions_tests.rb create mode 100644 tests/models/cdn/distribution_tests.rb create mode 100644 tests/models/cdn/distributions_tests.rb create mode 100644 tests/models/cdn/invalidation_tests.rb create mode 100644 tests/models/cdn/invalidations_tests.rb create mode 100644 tests/models/cdn/streaming_distribution_tests.rb create mode 100644 tests/models/cdn/streaming_distributions_tests.rb create mode 100644 tests/models/cloud_watch/alarm_data_tests.rb create mode 100644 tests/models/cloud_watch/alarm_history_tests.rb create mode 100644 tests/models/cloud_watch/metric_statistics_tests.rb create mode 100644 tests/models/cloud_watch/metrics_tests.rb create mode 100644 tests/models/compute/address_tests.rb create mode 100644 tests/models/compute/addresses_tests.rb create mode 100644 tests/models/compute/dhcp_option_tests.rb create mode 100644 tests/models/compute/dhcp_options_tests.rb create mode 100644 tests/models/compute/internet_gateway_tests.rb create mode 100644 tests/models/compute/internet_gateways_tests.rb create mode 100644 tests/models/compute/key_pair_tests.rb create mode 100644 tests/models/compute/key_pairs_tests.rb create mode 100644 tests/models/compute/network_acl_tests.rb create mode 100644 tests/models/compute/network_acls_tests.rb create mode 100644 tests/models/compute/network_interfaces_test.rb create mode 100644 tests/models/compute/security_group_tests.rb create mode 100644 tests/models/compute/security_groups_tests.rb create mode 100644 tests/models/compute/server_tests.rb create mode 100644 tests/models/compute/snapshot_tests.rb create mode 100644 tests/models/compute/snapshots_tests.rb create mode 100644 tests/models/compute/subnet_tests.rb create mode 100644 tests/models/compute/subnets_tests.rb create mode 100644 tests/models/compute/volume_tests.rb create mode 100644 tests/models/compute/volumes_tests.rb create mode 100644 tests/models/compute/vpc_tests.rb create mode 100644 tests/models/compute/vpcs_tests.rb create mode 100644 tests/models/data_pipeline/pipeline_tests.rb create mode 100644 tests/models/data_pipeline/pipelines_tests.rb create mode 100644 tests/models/dns/record_tests.rb create mode 100644 tests/models/dns/records_tests.rb create mode 100644 tests/models/dns/zone_tests.rb create mode 100644 tests/models/dns/zones_tests.rb create mode 100644 tests/models/elasticache/cluster_tests.rb create mode 100644 tests/models/elasticache/parameter_groups_tests.rb create mode 100644 tests/models/elasticache/security_groups_tests.rb create mode 100644 tests/models/elasticache/subnet_groups_tests.rb create mode 100644 tests/models/elb/model_tests.rb create mode 100644 tests/models/elb/tagging_tests.rb create mode 100644 tests/models/glacier/model_tests.rb create mode 100644 tests/models/iam/access_keys_tests.rb create mode 100644 tests/models/iam/policies_tests.rb create mode 100644 tests/models/iam/roles_tests.rb create mode 100644 tests/models/iam/users_tests.rb create mode 100644 tests/models/rds/event_subscription_tests.rb create mode 100644 tests/models/rds/event_subscriptions_tests.rb create mode 100644 tests/models/rds/helper.rb create mode 100644 tests/models/rds/instance_option_tests.rb create mode 100644 tests/models/rds/parameter_group_tests.rb create mode 100644 tests/models/rds/parameter_groups_tests.rb create mode 100644 tests/models/rds/security_group_tests.rb create mode 100644 tests/models/rds/security_groups_tests.rb create mode 100644 tests/models/rds/server_tests.rb create mode 100644 tests/models/rds/servers_tests.rb create mode 100644 tests/models/rds/snapshot_tests.rb create mode 100644 tests/models/rds/snapshots_tests.rb create mode 100644 tests/models/rds/tagging_tests.rb create mode 100644 tests/models/sns/topic_tests.rb create mode 100644 tests/models/sns/topics_tests.rb create mode 100644 tests/models/storage/directory_tests.rb create mode 100644 tests/models/storage/file_tests.rb create mode 100644 tests/models/storage/files_tests.rb create mode 100644 tests/models/storage/url_tests.rb create mode 100644 tests/models/storage/version_tests.rb create mode 100644 tests/models/storage/versions_tests.rb create mode 100644 tests/parsers/elb/describe_load_balancers.rb create mode 100644 tests/requests/auto_scaling/auto_scaling_tests.rb create mode 100644 tests/requests/auto_scaling/describe_types_tests.rb create mode 100644 tests/requests/auto_scaling/helper.rb create mode 100644 tests/requests/auto_scaling/model_tests.rb create mode 100644 tests/requests/auto_scaling/notification_configuration_tests.rb create mode 100644 tests/requests/auto_scaling/tag_tests.rb create mode 100644 tests/requests/beanstalk/application_tests.rb create mode 100644 tests/requests/beanstalk/solution_stack_tests.rb create mode 100644 tests/requests/cdn/cdn_tests.rb create mode 100644 tests/requests/cloud_formation/stack_tests.rb create mode 100644 tests/requests/cloud_watch/get_metric_statistics_tests.rb create mode 100644 tests/requests/cloud_watch/list_metrics_test.rb create mode 100644 tests/requests/cloud_watch/put_metric_data_tests.rb create mode 100644 tests/requests/compute/address_tests.rb create mode 100644 tests/requests/compute/assign_private_ip_tests.rb create mode 100644 tests/requests/compute/availability_zone_tests.rb create mode 100644 tests/requests/compute/client_tests.rb create mode 100644 tests/requests/compute/dhcp_options_tests.rb create mode 100644 tests/requests/compute/helper.rb create mode 100644 tests/requests/compute/image_tests.rb create mode 100644 tests/requests/compute/instance_tests.rb create mode 100644 tests/requests/compute/internet_gateway_tests.rb create mode 100644 tests/requests/compute/key_pair_tests.rb create mode 100644 tests/requests/compute/network_acl_tests.rb create mode 100644 tests/requests/compute/network_interface_tests.rb create mode 100644 tests/requests/compute/placement_group_tests.rb create mode 100644 tests/requests/compute/region_tests.rb create mode 100644 tests/requests/compute/route_tests.rb create mode 100644 tests/requests/compute/security_group_tests.rb create mode 100644 tests/requests/compute/snapshot_tests.rb create mode 100644 tests/requests/compute/spot_datafeed_subscription_tests.rb create mode 100644 tests/requests/compute/spot_instance_tests.rb create mode 100644 tests/requests/compute/spot_price_history_tests.rb create mode 100644 tests/requests/compute/subnet_tests.rb create mode 100644 tests/requests/compute/tag_tests.rb create mode 100644 tests/requests/compute/volume_tests.rb create mode 100644 tests/requests/compute/vpc_tests.rb create mode 100644 tests/requests/data_pipeline/helper.rb create mode 100644 tests/requests/data_pipeline/pipeline_tests.rb create mode 100644 tests/requests/dns/dns_tests.rb create mode 100644 tests/requests/dns/health_check_tests.rb create mode 100644 tests/requests/dns/helper.rb create mode 100644 tests/requests/dynamodb/item_tests.rb create mode 100644 tests/requests/dynamodb/table_tests.rb create mode 100644 tests/requests/elasticache/cache_cluster_tests.rb create mode 100644 tests/requests/elasticache/describe_events.rb create mode 100644 tests/requests/elasticache/describe_reserved_cache_nodes.rb create mode 100644 tests/requests/elasticache/helper.rb create mode 100644 tests/requests/elasticache/parameter_group_tests.rb create mode 100644 tests/requests/elasticache/security_group_tests.rb create mode 100644 tests/requests/elasticache/subnet_group_tests.rb create mode 100644 tests/requests/elb/helper.rb create mode 100644 tests/requests/elb/listener_tests.rb create mode 100644 tests/requests/elb/load_balancer_tests.rb create mode 100644 tests/requests/elb/policy_tests.rb create mode 100644 tests/requests/emr/helper.rb create mode 100644 tests/requests/emr/instance_group_tests.rb create mode 100644 tests/requests/emr/job_flow_tests.rb create mode 100644 tests/requests/glacier/archive_tests.rb create mode 100644 tests/requests/glacier/multipart_upload_tests.rb create mode 100644 tests/requests/glacier/tree_hash_tests.rb create mode 100644 tests/requests/glacier/vault_tests.rb create mode 100644 tests/requests/iam/access_key_tests.rb create mode 100644 tests/requests/iam/account_policy_tests.rb create mode 100644 tests/requests/iam/account_tests.rb create mode 100644 tests/requests/iam/group_policy_tests.rb create mode 100644 tests/requests/iam/group_tests.rb create mode 100644 tests/requests/iam/helper.rb create mode 100644 tests/requests/iam/login_profile_tests.rb create mode 100644 tests/requests/iam/mfa_tests.rb create mode 100644 tests/requests/iam/role_tests.rb create mode 100644 tests/requests/iam/server_certificate_tests.rb create mode 100644 tests/requests/iam/user_policy_tests.rb create mode 100644 tests/requests/iam/user_tests.rb create mode 100644 tests/requests/rds/describe_events.rb create mode 100644 tests/requests/rds/event_subscription_tests.rb create mode 100644 tests/requests/rds/helper.rb create mode 100644 tests/requests/rds/instance_option_tests.rb create mode 100644 tests/requests/rds/instance_tests.rb create mode 100644 tests/requests/rds/log_file_tests.rb create mode 100644 tests/requests/rds/parameter_group_tests.rb create mode 100644 tests/requests/rds/parameter_request_tests.rb create mode 100644 tests/requests/rds/security_group_tests.rb create mode 100644 tests/requests/rds/subnet_groups_tests.rb create mode 100644 tests/requests/rds/tagging_tests.rb create mode 100644 tests/requests/redshift/cluster_parameter_group_tests.rb create mode 100644 tests/requests/redshift/cluster_security_group_tests.rb create mode 100644 tests/requests/redshift/cluster_snapshot_tests.rb create mode 100644 tests/requests/redshift/cluster_tests.rb create mode 100644 tests/requests/ses/helper.rb create mode 100644 tests/requests/ses/verified_domain_identity_tests.rb create mode 100644 tests/requests/ses/verified_email_address_tests.rb create mode 100644 tests/requests/simpledb/attributes_tests.rb create mode 100644 tests/requests/simpledb/domain_tests.rb create mode 100644 tests/requests/simpledb/helper.rb create mode 100644 tests/requests/sns/helper.rb create mode 100644 tests/requests/sns/subscription_tests.rb create mode 100644 tests/requests/sns/topic_tests.rb create mode 100644 tests/requests/sqs/helper.rb create mode 100644 tests/requests/sqs/message_tests.rb create mode 100644 tests/requests/sqs/queue_tests.rb create mode 100644 tests/requests/storage/acl_utils_tests.rb create mode 100644 tests/requests/storage/bucket_tests.rb create mode 100644 tests/requests/storage/cors_utils_tests.rb create mode 100644 tests/requests/storage/delete_multiple_objects_tests.rb create mode 100644 tests/requests/storage/multipart_upload_tests.rb create mode 100644 tests/requests/storage/object_tests.rb create mode 100644 tests/requests/storage/versioning_tests.rb create mode 100644 tests/requests/sts/assume_role_tests.rb create mode 100644 tests/requests/sts/assume_role_with_saml_tests.rb create mode 100644 tests/requests/sts/get_federation_token_tests.rb create mode 100644 tests/requests/sts/session_token_tests.rb create mode 100644 tests/signaturev4_tests.rb create mode 100644 tests/signed_params_tests.rb create mode 100644 tests/storage_tests.rb diff --git a/fog-aws.gemspec b/fog-aws.gemspec index f8c6731bb..6aaf0cbb6 100644 --- a/fog-aws.gemspec +++ b/fog-aws.gemspec @@ -5,7 +5,7 @@ require 'fog/aws/version' Gem::Specification.new do |spec| spec.name = "fog-aws" - spec.version = Fog::Aws::VERSION + spec.version = Fog::AWS::VERSION spec.authors = ["Josh Lane"] spec.email = ["me@joshualane.com"] spec.summary = %q{Module for the 'fog' gem to support Amazon Web Services.} @@ -24,4 +24,6 @@ Gem::Specification.new do |spec| spec.add_dependency "fog-core" spec.add_dependency "fog-xml" + spec.add_dependency "fog-json" + spec.add_dependency "ipaddress" end diff --git a/lib/fog/aws.rb b/lib/fog/aws.rb index c41ff2a80..a08911249 100644 --- a/lib/fog/aws.rb +++ b/lib/fog/aws.rb @@ -1,7 +1,31 @@ -require "fog/aws/version" +require 'fog/aws/version' module Fog - module Aws - # Your code goes here... + module AWS end end + +require 'fog/aws/core' + +require 'fog/aws/auto_scaling' +require 'fog/aws/beanstalk' +require 'fog/aws/cdn' +require 'fog/aws/cloud_formation' +require 'fog/aws/cloud_watch' +require 'fog/aws/compute' +require 'fog/aws/data_pipeline' +require 'fog/aws/dns' +require 'fog/aws/dynamodb' +require 'fog/aws/elasticache' +require 'fog/aws/elb' +require 'fog/aws/emr' +require 'fog/aws/glacier' +require 'fog/aws/iam' +require 'fog/aws/rds' +require 'fog/aws/redshift' +require 'fog/aws/ses' +require 'fog/aws/simpledb' +require 'fog/aws/sns' +require 'fog/aws/sqs' +require 'fog/aws/storage' +require 'fog/aws/sts' diff --git a/lib/fog/aws/auto_scaling.rb b/lib/fog/aws/auto_scaling.rb new file mode 100644 index 000000000..8dad09fae --- /dev/null +++ b/lib/fog/aws/auto_scaling.rb @@ -0,0 +1,279 @@ +require 'fog/aws/core' + +module Fog + module AWS + class AutoScaling < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class IdentifierTaken < Fog::Errors::Error; end + class ResourceInUse < Fog::Errors::Error; end + class ValidationError < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :path, :port, :scheme, :persistent, :region, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/auto_scaling' + request :create_auto_scaling_group + request :create_launch_configuration + request :create_or_update_tags + request :delete_auto_scaling_group + request :delete_launch_configuration + request :delete_notification_configuration + request :delete_policy + request :delete_scheduled_action + request :delete_tags + request :describe_adjustment_types + request :describe_auto_scaling_groups + request :describe_auto_scaling_instances + request :describe_auto_scaling_notification_types + request :describe_launch_configurations + request :describe_metric_collection_types + request :describe_notification_configurations + request :describe_policies + request :describe_scaling_activities + request :describe_scaling_process_types + request :describe_scheduled_actions + request :describe_tags + request :describe_termination_policy_types + request :disable_metrics_collection + request :enable_metrics_collection + request :execute_policy + request :put_notification_configuration + request :put_scaling_policy + request :put_scheduled_update_group_action + request :resume_processes + request :set_desired_capacity + request :set_instance_health + request :suspend_processes + request :terminate_instance_in_auto_scaling_group + request :update_auto_scaling_group + + model_path 'fog/aws/models/auto_scaling' + model :activity + collection :activities + model :configuration + collection :configurations + model :group + collection :groups + model :instance + collection :instances + model :policy + collection :policies + + ExpectedOptions = {} + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + + attr_accessor :region + + # Initialize connection to AutoScaling + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # as = AutoScaling.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * AutoScaling object with connection to Aws. + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + + @connection_options = options[:connection_options] || {} + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.auto_scaling' + + options[:region] ||= 'us-east-1' + @region = options[:region] + + @host = options[:host] || "autoscaling.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @port = options[:port] || 443 + @persistent = options[:persistent] || false + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + end + + def reload + @connection.reset + end + + private + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Aws.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :aws_session_token => @aws_session_token, + :method => 'POST', + :signer => @signer, + :host => @host, + :path => @path, + :port => @port, + :version => '2011-01-01' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + begin + @connection.request({ + :body => body, + :expects => 200, + :idempotent => idempotent, + :headers => headers, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'AlreadyExists' + Fog::AWS::AutoScaling::IdentifierTaken.slurp(error, match[:message]) + when 'ResourceInUse' + Fog::AWS::AutoScaling::ResourceInUse.slurp(error, match[:message]) + when 'ValidationError' + Fog::AWS::AutoScaling::ValidationError.slurp(error, match[:message]) + else + Fog::AWS::AutoScaling::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'autoscaling') + end + end + + class Mock + include Fog::AWS::CredentialFetcher::ConnectionMethods + + attr_accessor :region + + def self.data + @data ||= Hash.new do |hash, region| + owner_id = Fog::AWS::Mock.owner_id + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :adjustment_types => [ + 'ChangeInCapacity', + 'ExactCapacity', + 'PercentChangeInCapacity' + ], + :auto_scaling_groups => {}, + :scaling_policies => {}, + :health_states => [ + 'Healthy', + 'Unhealthy' + ], + :launch_configurations => {}, + :metric_collection_types => { + :granularities => [ + '1Minute' + ], + :metrics => [ + 'GroupMinSize', + 'GroupMaxSize', + 'GroupDesiredCapacity', + 'GroupInServiceInstances', + 'GroupPendingInstances', + 'GroupTerminatingInstances', + 'GroupTotalInstances' + ] + }, + :notification_configurations => {}, + :notification_types => [ + 'autoscaling:EC2_INSTANCE_LAUNCH', + 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR', + 'autoscaling:EC2_INSTANCE_TERMINATE', + 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR', + 'autoscaling:TEST_NOTIFICATION' + ], + :owner_id => owner_id, + :process_types => [ + 'AZRebalance', + 'AddToLoadBalancer', + 'AlarmNotification', + 'HealthCheck', + 'Launch', + 'ReplaceUnhealthy', + 'ScheduledActions', + 'Terminate' + ], + :termination_policy_types => [ + 'ClosestToNextInstanceHour', + 'Default', + 'NewestInstance', + 'OldestInstance', + 'OldestLaunchConfiguration' + ] + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @region = options[:region] || 'us-east-1' + + unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'sa-east-1', 'us-east-1', 'us-west-1', 'us-west-2'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def region_data + self.class.data[@region] + end + + def data + self.region_data[@aws_access_key_id] + end + + def reset_data + self.region_data.delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + end + end +end diff --git a/lib/fog/aws/beanstalk.rb b/lib/fog/aws/beanstalk.rb new file mode 100644 index 000000000..a00bf105d --- /dev/null +++ b/lib/fog/aws/beanstalk.rb @@ -0,0 +1,156 @@ +require 'fog/aws/core' + +module Fog + module AWS + class ElasticBeanstalk < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class InvalidParameterError < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/beanstalk' + + request :check_dns_availability + request :create_application + request :create_application_version + request :create_configuration_template + request :create_environment + request :create_storage_location + request :delete_application + request :delete_application_version + request :delete_configuration_template + request :delete_environment_configuration + request :describe_applications + request :describe_application_versions + request :describe_configuration_options + request :describe_configuration_settings + request :describe_environment_resources + request :describe_environments + request :describe_events + request :list_available_solution_stacks + request :rebuild_environment + request :request_environment_info + request :restart_app_server + request :retrieve_environment_info + request :swap_environment_cnames + request :terminate_environment + request :update_application + request :update_application_version + request :update_configuration_template + request :update_environment + request :validate_configuration_settings + + model_path 'fog/aws/models/beanstalk' + + model :application + collection :applications + model :environment + collection :environments + model :event + collection :events + model :template + collection :templates + model :version + collection :versions + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + + @connection_options = options[:connection_options] || {} + options[:region] ||= 'us-east-1' + @host = options[:host] || "elasticbeanstalk.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.beanstalk' + + @region = options[:region] + setup_credentials(options) + end + + def reload + @connection.reset + end + + # Returns an array of available solutions stack details + def solution_stacks + list_available_solution_stacks.body['ListAvailableSolutionStacksResult']['SolutionStackDetails'] + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'elasticbeanstalk') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Aws.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :signer => @signer, + :aws_session_token => @aws_session_token, + :method => "POST", + :host => @host, + :path => @path, + :port => @port, + :version => '2010-12-01' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'InvalidParameterValue' + Fog::AWS::ElasticBeanstalk::InvalidParameterError.slurp(error, match[:message]) + else + Fog::AWS::ElasticBeanstalk::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/cdn.rb b/lib/fog/aws/cdn.rb new file mode 100644 index 000000000..0665416e1 --- /dev/null +++ b/lib/fog/aws/cdn.rb @@ -0,0 +1,205 @@ +require 'fog/aws/core' + +module Fog + module CDN + class Aws < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :path, :port, :scheme, :version, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + model_path 'fog/aws/models/cdn' + model :distribution + collection :distributions + model :streaming_distribution + collection :streaming_distributions + + request_path 'fog/aws/requests/cdn' + request 'delete_distribution' + request 'delete_streaming_distribution' + request 'get_distribution' + request 'get_distribution_list' + request 'get_invalidation_list' + request 'get_invalidation' + request 'get_streaming_distribution' + request 'get_streaming_distribution_list' + request 'post_distribution' + request 'post_streaming_distribution' + request 'post_invalidation' + request 'put_distribution_config' + request 'put_streaming_distribution_config' + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :distributions => {}, + :streaming_distributions => {}, + :invalidations => {} + } + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + end + + def data + self.class.data[@aws_access_key_id] + end + + def reset_data + self.class.data.delete(@aws_access_key_id) + end + + def signature(params) + "foo" + end + + def setup_credentials(options={}) + @aws_access_key_id = options[:aws_access_key_id] + end + + def self.distribution_id + random_id(14) + end + + def self.generic_id + random_id(14) + end + + def self.domain_name + "#{random_id(12).downcase}.cloudfront.net" + end + + def self.random_id(length) + Fog::Mock.random_selection("abcdefghijklmnopqrstuvwxyz0123456789", length).upcase + end + + CDN_ERRORS = { + :access_denies => {:code => 'AccessDenied',:msg => 'Access denied.',:status => 403}, + :inappropriate_xml => {:code => 'InappropriateXML',:msg => 'The XML document you provided was well-formed and valid, but not appropriate for this operation.',:status => 400}, + :internal_error => {:code => 'InternalError',:msg => 'We encountered an internal error. Please try again.',:status => 500}, + :invalid_action => {:code => 'InvalidAction',:msg => 'The action specified is not valid.',:status => 400}, + :invalid_argument => {:code => 'InvalidArgument',:msg => '%s', :status => 400}, + :not_implemented => {:code => 'NotImplemented', :msg => 'Not implemented.',:status => 501}, + :no_such_distribution => { :code => 'NoSuchDistribution', :msg => 'The specified distribution does not exist', :status => 404 }, + :no_such_streaming_distribution => { :code => 'NoSuchStreamingDistribution', :msg => 'The specified streaming distribution does not exist', :status => 404 }, + :no_such_invalidation => { :code => 'NoSuchInvalidation', :msg => 'The specified invalidation does not exist', :status => 404 }, + :cname_exists => { :code => 'CNAMEAlreadyExists', :msg => 'One or more of the CNAMEs you provided are already associated with a different distribution', :status => 409 }, + :illegal_update => { :code => 'IllegalUpdate', :msg => 'Origin and CallerReference cannot be updated.', :status => 400 }, + :invalid_if_match_version => { :code => 'InvalidIfMatchVersion', :msg => 'The If-Match version is missing or not valid for the distribution.', :status => 400}, + :distribution_not_disabled => { :code => 'DistributionNotDisabled', :msg => 'The distribution you are trying to delete has not been disabled.', :status => 409 }, + + } + + def self.error(code, argument = '') + if error = CDN_ERRORS[code] + raise_error(error[:status], error[:code], error[:msg] % argument) + end + end + + def self.raise_error(status, code, message='') + response = Excon::Response.new + response.status = status + response.body = < + + Sender + #{code} + #{message}. + + #{Fog::AWS::Mock.request_id} + +EOF + + raise(Excon::Errors.status_error({:expects => 201}, response)) + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to Cloudfront + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # cdn = Fog::AWS::CDN.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * cdn object with connection to aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.cdn' + @connection_options = options[:connection_options] || {} + @host = options[:host] || 'cloudfront.amazonaws.com' + @path = options[:path] || '/' + @persistent = options.fetch(:persistent, true) + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @version = options[:version] || '2010-11-01' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @hmac = Fog::HMAC.new('sha1', @aws_secret_access_key) + end + + def request(params, &block) + refresh_credentials_if_expired + + params[:headers] ||= {} + params[:headers]['Date'] = Fog::Time.now.to_date_header + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params[:headers]['Authorization'] = "Aws #{@aws_access_key_id}:#{signature(params)}" + params[:path] = "/#{@version}/#{params[:path]}" + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(params, &block) + end + else + _request(params, &block) + end + end + + def _request(params, &block) + @connection.request(params, &block) + end + + def signature(params) + string_to_sign = params[:headers]['Date'] + signed_string = @hmac.sign(string_to_sign) + Base64.encode64(signed_string).chomp! + end + end + end + end +end diff --git a/lib/fog/aws/cloud_formation.rb b/lib/fog/aws/cloud_formation.rb new file mode 100644 index 000000000..fca47b7ba --- /dev/null +++ b/lib/fog/aws/cloud_formation.rb @@ -0,0 +1,133 @@ +require 'fog/aws/core' + +module Fog + module AWS + class CloudFormation < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :path, :port, :scheme, :persistent, :region, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/cloud_formation' + request :create_stack + request :update_stack + request :delete_stack + request :describe_stack_events + request :describe_stack_resources + request :describe_stacks + request :get_template + request :validate_template + request :list_stacks + request :list_stack_resources + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to CloudFormation + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # cf = CloudFormation.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * CloudFormation object with connection to Aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.cloud_formation' + @connection_options = options[:connection_options] || {} + options[:region] ||= 'us-east-1' + @region = options[:region] + @host = options[:host] || "cloudformation.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'cloudformation') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :signer => @signer, + :aws_session_token => @aws_session_token, + :host => @host, + :path => @path, + :port => @port, + :version => '2010-05-15', + :method => 'POST' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :idempotent => idempotent, + :headers => headers, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'NotFound', 'ValidationError' + Fog::AWS::CloudFormation::NotFound.slurp(error, match[:message]) + else + Fog::AWS::CloudFormation::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/cloud_watch.rb b/lib/fog/aws/cloud_watch.rb new file mode 100644 index 000000000..34f6306e8 --- /dev/null +++ b/lib/fog/aws/cloud_watch.rb @@ -0,0 +1,167 @@ +require 'fog/aws/core' + +module Fog + module AWS + class CloudWatch < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/cloud_watch' + + request :list_metrics + request :get_metric_statistics + request :put_metric_data + request :describe_alarms + request :put_metric_alarm + request :delete_alarms + request :describe_alarm_history + request :enable_alarm_actions + request :disable_alarm_actions + request :describe_alarms_for_metric + request :set_alarm_state + + model_path 'fog/aws/models/cloud_watch' + model :metric + collection :metrics + model :metric_statistic + collection :metric_statistics + model :alarm_datum + collection :alarm_data + model :alarm_history + collection :alarm_histories + model :alarm + collection :alarms + + class Mock + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :metric_alarms => {} + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @aws_access_key_id = options[:aws_access_key_id] + + @region = options[:region] || 'us-east-1' + + unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'sa-east-1', 'us-east-1', 'us-west-1', 'us-west-2'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to Cloudwatch + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # elb = CloudWatch.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'eu-west-1', 'us-east-1', etc. + # + # ==== Returns + # * CloudWatch object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + + @connection_options = options[:connection_options] || {} + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.cloud_watch' + + options[:region] ||= 'us-east-1' + @region = options[:region] + @host = options[:host] || "monitoring.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'monitoring') + end + + def request(params) + refresh_credentials_if_expired + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Aws.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :signer => @signer, + :aws_session_token => @aws_session_token, + :host => @host, + :path => @path, + :port => @port, + :version => '2010-08-01', + :method => 'POST' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + end + end + end + end +end diff --git a/lib/fog/aws/compute.rb b/lib/fog/aws/compute.rb new file mode 100644 index 000000000..d1b97da8b --- /dev/null +++ b/lib/fog/aws/compute.rb @@ -0,0 +1,543 @@ +require 'fog/aws/core' + +module Fog + module Compute + class Aws < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :endpoint, :region, :host, :path, :port, :scheme, :persistent, :aws_session_token, :use_iam_profile, :aws_credentials_expire_at, :instrumentor, :instrumentor_name, :version + + secrets :aws_secret_access_key, :hmac, :aws_session_token + + model_path 'fog/aws/models/compute' + model :address + collection :addresses + model :dhcp_options + collection :dhcp_options + model :flavor + collection :flavors + model :image + collection :images + model :internet_gateway + collection :internet_gateways + model :key_pair + collection :key_pairs + model :network_acl + collection :network_acls + model :network_interface + collection :network_interfaces + model :route_table + collection :route_tables + model :security_group + collection :security_groups + model :server + collection :servers + model :snapshot + collection :snapshots + model :tag + collection :tags + model :volume + collection :volumes + model :spot_request + collection :spot_requests + model :subnet + collection :subnets + model :vpc + collection :vpcs + + request_path 'fog/aws/requests/compute' + request :allocate_address + request :assign_private_ip_addresses + request :associate_address + request :associate_dhcp_options + request :attach_network_interface + request :associate_route_table + request :attach_internet_gateway + request :attach_volume + request :authorize_security_group_ingress + request :cancel_spot_instance_requests + request :create_dhcp_options + request :create_internet_gateway + request :create_image + request :create_key_pair + request :create_network_acl + request :create_network_acl_entry + request :create_network_interface + request :create_placement_group + request :create_route + request :create_route_table + request :create_security_group + request :create_snapshot + request :create_spot_datafeed_subscription + request :create_subnet + request :create_tags + request :create_volume + request :create_vpc + request :copy_image + request :copy_snapshot + request :delete_dhcp_options + request :delete_internet_gateway + request :delete_key_pair + request :delete_network_acl + request :delete_network_acl_entry + request :delete_network_interface + request :delete_security_group + request :delete_placement_group + request :delete_route + request :delete_route_table + request :delete_snapshot + request :delete_spot_datafeed_subscription + request :delete_subnet + request :delete_tags + request :delete_volume + request :delete_vpc + request :deregister_image + request :describe_account_attributes + request :describe_addresses + request :describe_availability_zones + request :describe_dhcp_options + request :describe_images + request :describe_instances + request :describe_internet_gateways + request :describe_reserved_instances + request :describe_instance_status + request :describe_key_pairs + request :describe_network_acls + request :describe_network_interface_attribute + request :describe_network_interfaces + request :describe_route_tables + request :describe_placement_groups + request :describe_regions + request :describe_reserved_instances_offerings + request :describe_security_groups + request :describe_snapshots + request :describe_spot_datafeed_subscription + request :describe_spot_instance_requests + request :describe_spot_price_history + request :describe_subnets + request :describe_tags + request :describe_volumes + request :describe_volume_status + request :describe_vpcs + request :describe_vpc_attribute + request :detach_network_interface + request :detach_internet_gateway + request :detach_volume + request :disassociate_address + request :disassociate_route_table + request :get_console_output + request :get_password_data + request :import_key_pair + request :modify_image_attribute + request :modify_instance_attribute + request :modify_network_interface_attribute + request :modify_snapshot_attribute + request :modify_subnet_attribute + request :modify_volume_attribute + request :modify_vpc_attribute + request :purchase_reserved_instances_offering + request :reboot_instances + request :release_address + request :replace_network_acl_association + request :replace_network_acl_entry + request :replace_route + request :register_image + request :request_spot_instances + request :reset_network_interface_attribute + request :revoke_security_group_ingress + request :run_instances + request :terminate_instances + request :start_instances + request :stop_instances + request :monitor_instances + request :unmonitor_instances + + class InvalidURIError < Exception; end + + # deprecation + class Real + def modify_image_attributes(*params) + Fog::Logger.deprecation("modify_image_attributes is deprecated, use modify_image_attribute instead [light_black](#{caller.first})[/]") + modify_image_attribute(*params) + end + + # http://docs.aws.amazon.com/AwsEC2/latest/UserGuide/ec2-supported-platforms.html + def supported_platforms + describe_account_attributes.body["accountAttributeSet"].find{ |h| h["attributeName"] == "supported-platforms" }["values"] + end + end + + class Mock + MOCKED_TAG_TYPES = { + 'ami' => 'image', + 'i' => 'instance', + 'snap' => 'snapshot', + 'vol' => 'volume', + 'igw' => 'internet_gateway', + 'acl' => 'network_acl', + 'vpc' => 'vpc' + } + + include Fog::AWS::CredentialFetcher::ConnectionMethods + include Fog::AWS::RegionMethods + + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + owner_id = Fog::AWS::Mock.owner_id + security_group_id = Fog::AWS::Mock.security_group_id + region_hash[key] = { + :deleted_at => {}, + :addresses => {}, + :images => {}, + :image_launch_permissions => Hash.new do |permissions_hash, image_key| + permissions_hash[image_key] = { + :users => [] + } + end, + :instances => {}, + :reserved_instances => {}, + :key_pairs => {}, + :limits => { :addresses => 5 }, + :owner_id => owner_id, + :security_groups => { + 'default' => { + 'groupDescription' => 'default group', + 'groupName' => 'default', + 'groupId' => security_group_id, + 'ipPermissionsEgress' => [], + 'ipPermissions' => [ + { + 'groups' => [{'groupName' => 'default', 'userId' => owner_id, 'groupId' => security_group_id }], + 'fromPort' => -1, + 'toPort' => -1, + 'ipProtocol' => 'icmp', + 'ipRanges' => [] + }, + { + 'groups' => [{'groupName' => 'default', 'userId' => owner_id, 'groupId' => security_group_id}], + 'fromPort' => 0, + 'toPort' => 65535, + 'ipProtocol' => 'tcp', + 'ipRanges' => [] + }, + { + 'groups' => [{'groupName' => 'default', 'userId' => owner_id, 'groupId' => security_group_id}], + 'fromPort' => 0, + 'toPort' => 65535, + 'ipProtocol' => 'udp', + 'ipRanges' => [] + } + ], + 'ownerId' => owner_id + }, + 'amazon-elb-sg' => { + 'groupDescription' => 'amazon-elb-sg', + 'groupName' => 'amazon-elb-sg', + 'groupId' => 'amazon-elb', + 'ownerId' => 'amazon-elb', + 'ipPermissionsEgree' => [], + 'ipPermissions' => [], + }, + }, + :network_acls => {}, + :network_interfaces => {}, + :snapshots => {}, + :volumes => {}, + :internet_gateways => {}, + :tags => {}, + :tag_sets => Hash.new do |tag_set_hash, resource_id| + tag_set_hash[resource_id] = {} + end, + :subnets => [], + :vpcs => [], + :dhcp_options => [], + :route_tables => [], + :account_attributes => [ + { + "values" => ["5"], + "attributeName" => "vpc-max-security-groups-per-interface" + }, + { + "values" => ["20"], + "attributeName" => "max-instances" + }, + { + "values" => ["EC2", "VPC"], + "attributeName" => "supported-platforms" + }, + { + "values" => ["none"], + "attributeName" => "default-vpc" + }, + { + "values" => ["5"], + "attributeName" => "max-elastic-ips" + }, + { + "values" => ["5"], + "attributeName" => "vpc-max-elastic-ips" + } + ] + } + end + end + end + + def self.reset + @data = nil + end + + attr_accessor :region + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @aws_credentials_expire_at = Time::now + 20 + setup_credentials(options) + @region = options[:region] || 'us-east-1' + + if @endpoint = options[:endpoint] + endpoint = URI.parse(@endpoint) + @host = endpoint.host or raise InvalidURIError.new("could not parse endpoint: #{@endpoint}") + @path = endpoint.path + @port = endpoint.port + @scheme = endpoint.scheme + else + @host = options[:host] || "ec2.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + end + validate_aws_region(@host, @region) + end + + def region_data + self.class.data[@region] + end + + def data + self.region_data[@aws_access_key_id] + end + + def reset_data + self.region_data.delete(@aws_access_key_id) + end + + def visible_images + images = self.data[:images].values.reduce({}) do |h, image| + h.update(image['imageId'] => image) + end + + self.region_data.each do |aws_access_key_id, data| + data[:image_launch_permissions].each do |image_id, list| + if list[:users].include?(self.data[:owner_id]) + images.update(image_id => data[:images][image_id]) + end + end + end + + images + end + + def supported_platforms + describe_account_attributes.body["accountAttributeSet"].find{ |h| h["attributeName"] == "supported-platforms" }["values"] + end + + def enable_ec2_classic + set_supported_platforms(%w[EC2 VPC]) + end + + def disable_ec2_classic + set_supported_platforms(%w[VPC]) + end + + def set_supported_platforms(values) + self.data[:account_attributes].find { |h| h["attributeName"] == "supported-platforms" }["values"] = values + end + + def tagged_resources(resources) + Array(resources).map do |resource_id| + if match = resource_id.match(/^(\w+)-[a-z0-9]{8}/i) + id = match.captures.first + else + raise(Fog::Service::NotFound.new("Unknown resource id #{resource_id}")) + end + + if MOCKED_TAG_TYPES.has_key? id + type = MOCKED_TAG_TYPES[id] + else + raise(Fog::Service::NotFound.new("Mocking tags of resource #{resource_id} has not been implemented")) + end + + case type + when 'image' + unless visible_images.has_key? resource_id + raise(Fog::Service::NotFound.new("Cannot tag #{resource_id}, the image does not exist")) + end + when 'vpc' + if self.data[:vpcs].select {|v| v['vpcId'] == resource_id }.empty? + raise(Fog::Service::NotFound.new("Cannot tag #{resource_id}, the vpc does not exist")) + end + else + unless self.data[:"#{type}s"][resource_id] + raise(Fog::Service::NotFound.new("Cannot tag #{resource_id}, the #{type} does not exist")) + end + end + { 'resourceId' => resource_id, 'resourceType' => type } + end + end + + + def apply_tag_filters(resources, filters, resource_id_key) + tag_set_fetcher = lambda {|resource| self.data[:tag_sets][resource[resource_id_key]] } + + # tag-key: match resources tagged with this key (any value) + if filters.key?('tag-key') + value = filters.delete('tag-key') + resources = resources.select{|r| tag_set_fetcher[r].key?(value)} + end + + # tag-value: match resources tagged with this value (any key) + if filters.key?('tag-value') + value = filters.delete('tag-value') + resources = resources.select{|r| tag_set_fetcher[r].values.include?(value)} + end + + # tag:key: match resources tagged with a key-value pair. Value may be an array, which is OR'd. + tag_filters = {} + filters.keys.each do |key| + tag_filters[key.gsub('tag:', '')] = filters.delete(key) if /^tag:/ =~ key + end + for tag_key, tag_value in tag_filters + resources = resources.select{|r| tag_value == tag_set_fetcher[r][tag_key]} + end + + resources + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + include Fog::AWS::RegionMethods + # Initialize connection to EC2 + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # sdb = SimpleDB.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, + # 'eu-west-1', 'us-east-1', and etc. + # * aws_session_token<~String> - when using Session Tokens or Federated Users, a session_token must be presented + # + # ==== Returns + # * EC2 object with connection to aws. + + attr_accessor :region + + def initialize(options={}) + + @connection_options = options[:connection_options] || {} + @region = options[:region] ||= 'us-east-1' + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.compute' + @version = options[:version] || '2014-06-15' + + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + + if @endpoint = options[:endpoint] + endpoint = URI.parse(@endpoint) + @host = endpoint.host or raise InvalidURIError.new("could not parse endpoint: #{@endpoint}") + @path = endpoint.path + @port = endpoint.port + @scheme = endpoint.scheme + else + @host = options[:host] || "ec2.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + end + + validate_aws_region(@host, @region) + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + def reload + @connection.reset + end + + private + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'ec2') + end + + def request(params) + refresh_credentials_if_expired + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + {'Content-Type' => 'application/x-www-form-urlencoded'}, + { + :host => @host, + :path => @path, + :port => @port, + :version => @version, + :signer => @signer, + :aws_session_token => @aws_session_token, + :method => "POST" + } + ) + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'NotFound', 'Unknown' + Fog::Compute::AWS::NotFound.slurp(error, match[:message]) + else + Fog::Compute::AWS::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/core.rb b/lib/fog/aws/core.rb new file mode 100644 index 000000000..914e9afe9 --- /dev/null +++ b/lib/fog/aws/core.rb @@ -0,0 +1,343 @@ +require 'fog/core' +require 'fog/xml' +require 'fog/json' +require 'fog/aws/credential_fetcher' +require 'fog/aws/region_methods' +require 'fog/aws/signaturev4' + +module Fog + module AWS + extend Fog::Provider + + service(:auto_scaling, 'AutoScaling') + service(:beanstalk, 'ElasticBeanstalk') + service(:cdn, 'CDN') + service(:compute, 'Compute') + service(:cloud_formation, 'CloudFormation') + service(:cloud_watch, 'CloudWatch') + service(:data_pipeline, 'DataPipeline') + service(:dynamodb, 'DynamoDB') + service(:dns, 'DNS') + service(:elasticache, 'Elasticache') + service(:elb, 'ELB') + service(:emr, 'EMR') + service(:glacier, 'Glacier') + service(:iam, 'IAM') + service(:rds, 'RDS') + service(:redshift, 'Redshift') + service(:ses, 'SES') + service(:simpledb, 'SimpleDB') + service(:sns, 'SNS') + service(:sqs, 'SQS') + service(:sts, 'STS') + service(:storage, 'Storage') + + def self.indexed_param(key, values) + params = {} + unless key.include?('%d') + key << '.%d' + end + [*values].each_with_index do |value, index| + if value.respond_to?('keys') + k = format(key, index + 1) + value.each do | vkey, vvalue | + params["#{k}.#{vkey}"] = vvalue + end + else + params[format(key, index + 1)] = value + end + end + params + end + + def self.serialize_keys(key, value, options = {}) + case value + when Hash + value.each do | k, v | + options.merge!(serialize_keys("#{key}.#{k}", v)) + end + return options + when Array + value.each_with_index do | it, idx | + options.merge!(serialize_keys("#{key}.member.#{(idx + 1)}", it)) + end + return options + else + return {key => value} + end + end + + def self.indexed_request_param(name, values) + idx = -1 + Array(values).reduce({}) do |params, value| + params["#{name}.#{idx += 1}"] = value + params + end + end + + def self.indexed_filters(filters) + params = {} + filters.keys.each_with_index do |key, key_index| + key_index += 1 + params[format('Filter.%d.Name', key_index)] = key + [*filters[key]].each_with_index do |value, value_index| + value_index += 1 + params[format('Filter.%d.Value.%d', key_index, value_index)] = value + end + end + params + end + + def self.escape(string) + string.gsub(/([^a-zA-Z0-9_.\-~]+)/) { + "%" + $1.unpack("H2" * $1.bytesize).join("%").upcase + } + end + + def self.signed_params_v4(params, headers, options={}) + date = Fog::Time.now + + params = params.merge('Version' => options[:version]) + + headers = headers.merge('Host' => options[:host], 'x-amz-date' => date.to_iso8601_basic) + headers['x-amz-security-token'] = options[:aws_session_token] if options[:aws_session_token] + + body = '' + for key in params.keys.sort + unless (value = params[key]).nil? + body << "#{key}=#{escape(value.to_s)}&" + end + end + body.chop! + + headers['Authorization'] = options[:signer].sign({:method => options[:method], :headers => headers, :body => body, :query => {}, :path => options[:path]}, date) + + return body, headers + end + + def self.signed_params(params, options = {}) + params.merge!({ + 'AwsAccessKeyId' => options[:aws_access_key_id], + 'SignatureMethod' => 'HmacSHA256', + 'SignatureVersion' => '2', + 'Timestamp' => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"), + 'Version' => options[:version] + }) + + params.merge!({ + 'SecurityToken' => options[:aws_session_token] + }) if options[:aws_session_token] + + body = '' + for key in params.keys.sort + unless (value = params[key]).nil? + body << "#{key}=#{escape(value.to_s)}&" + end + end + string_to_sign = "POST\n#{options[:host]}:#{options[:port]}\n#{options[:path]}\n" << body.chop + signed_string = options[:hmac].sign(string_to_sign) + body << "Signature=#{escape(Base64.encode64(signed_string).chomp!)}" + + body + end + + class Mock + def self.arn(vendor, account_id, path, region = nil) + "arn:aws:#{vendor}:#{region}:#{account_id}:#{path}" + end + + def self.availability_zone(region) + "#{region}#{Fog::Mock.random_selection('abcd', 1)}" + end + + def self.box_usage + sprintf("%0.10f", rand / 100).to_f + end + + def self.console_output + # "[ 0.000000] Linux version 2.6.18-xenU-ec2-v1.2 (root@domU-12-31-39-07-51-82) (gcc version 4.1.2 20070626 (Red Hat 4.1.2-13)) #2 SMP Wed Aug 19 09:04:38 EDT 2009" + Base64.decode64("WyAwLjAwMDAwMF0gTGludXggdmVyc2lvbiAyLjYuMTgteGVuVS1lYzItdjEu\nMiAocm9vdEBkb21VLTEyLTMxLTM5LTA3LTUxLTgyKSAoZ2NjIHZlcnNpb24g\nNC4xLjIgMjAwNzA2MjYgKFJlZCBIYXQgNC4xLjItMTMpKSAjMiBTTVAgV2Vk\nIEF1ZyAxOSAwOTowNDozOCBFRFQgMjAwOQ==\n") + end + + def self.dns_name_for(ip_address) + "ec2-#{ip_address.gsub('.','-')}.compute-1.amazonaws.com" + end + + def self.private_dns_name_for(ip_address) + "ip-#{ip_address.gsub('.','-')}.ec2.internal" + end + + def self.image + path = [] + (rand(3) + 2).times do + path << Fog::Mock.random_letters(rand(9) + 8) + end + { + "imageOwnerId" => Fog::Mock.random_letters(rand(5) + 4), + "blockDeviceMapping" => [], + "productCodes" => [], + "kernelId" => kernel_id, + "ramdiskId" => ramdisk_id, + "imageState" => "available", + "imageId" => image_id, + "architecture" => "i386", + "isPublic" => true, + "imageLocation" => path.join('/'), + "imageType" => "machine", + "rootDeviceType" => ["ebs","instance-store"][rand(2)], + "rootDeviceName" => "/dev/sda1" + } + end + + def self.image_id + "ami-#{Fog::Mock.random_hex(8)}" + end + + def self.key_fingerprint + fingerprint = [] + 20.times do + fingerprint << Fog::Mock.random_hex(2) + end + fingerprint.join(':') + end + + def self.instance_id + "i-#{Fog::Mock.random_hex(8)}" + end + + def self.ip_address + Fog::Mock.random_ip + end + + def self.private_ip_address + ip_address.gsub(/^\d{1,3}\./,"10.") + end + + def self.kernel_id + "aki-#{Fog::Mock.random_hex(8)}" + end + + def self.key_material + OpenSSL::PKey::RSA.generate(1024).to_s + end + + def self.owner_id + Fog::Mock.random_numbers(12) + end + + def self.ramdisk_id + "ari-#{Fog::Mock.random_hex(8)}" + end + + def self.request_id + request_id = [] + request_id << Fog::Mock.random_hex(8) + 3.times do + request_id << Fog::Mock.random_hex(4) + end + request_id << Fog::Mock.random_hex(12) + request_id.join('-') + end + class << self + alias_method :reserved_instances_id, :request_id + alias_method :reserved_instances_offering_id, :request_id + alias_method :sqs_message_id, :request_id + alias_method :sqs_sender_id, :request_id + end + + def self.reservation_id + "r-#{Fog::Mock.random_hex(8)}" + end + + def self.snapshot_id + "snap-#{Fog::Mock.random_hex(8)}" + end + + def self.volume_id + "vol-#{Fog::Mock.random_hex(8)}" + end + + def self.security_group_id + "sg-#{Fog::Mock.random_hex(8)}" + end + + def self.network_acl_id + "acl-#{Fog::Mock.random_hex(8)}" + end + def self.network_acl_association_id + "aclassoc-#{Fog::Mock.random_hex(8)}" + end + def self.network_interface_id + "eni-#{Fog::Mock.random_hex(8)}" + end + def self.internet_gateway_id + "igw-#{Fog::Mock.random_hex(8)}" + end + def self.dhcp_options_id + "dopt-#{Fog::Mock.random_hex(8)}" + end + def self.vpc_id + "vpc-#{Fog::Mock.random_hex(8)}" + end + def self.subnet_id + "subnet-#{Fog::Mock.random_hex(8)}" + end + def self.zone_id + "zone-#{Fog::Mock.random_hex(8)}" + end + def self.change_id + Fog::Mock.random_letters_and_numbers(14) + end + def self.nameservers + [ + 'ns-2048.awsdns-64.com', + 'ns-2049.awsdns-65.net', + 'ns-2050.awsdns-66.org', + 'ns-2051.awsdns-67.co.uk' + ] + end + + def self.key_id(length=21) + #Probably close enough + Fog::Mock.random_selection('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',length) + end + + def self.rds_address(db_name,region) + "#{db_name}.#{Fog::Mock.random_letters(rand(12) + 4)}.#{region}.rds.amazonaws.com" + end + end + + def self.parse_security_group_options(group_name, options) + options ||= Hash.new + if group_name.is_a?(Hash) + options = group_name + elsif group_name + if options.key?('GroupName') + raise Fog::Compute::AWS::Error, 'Arguments specified both group_name and GroupName in options' + end + options = options.clone + options['GroupName'] = group_name + end + name_specified = options.key?('GroupName') && !options['GroupName'].nil? + group_id_specified = options.key?('GroupId') && !options['GroupId'].nil? + unless name_specified || group_id_specified + raise Fog::Compute::AWS::Error, 'Neither GroupName nor GroupId specified' + end + if name_specified && group_id_specified + options.delete('GroupName') + end + options + end + + module Errors + def self.match_error(error) + matcher = lambda {|s| s.match(/(?:.*(.*)<\/Code>)(?:.*(.*)<\/Message>)/m)} + [error.message, error.response.body].each(&Proc.new {|s| + match = matcher.call(s) + return {:code => match[1].split('.').last, :message => match[2]} if match + }) + {} # we did not match the message or response body + end + end + end +end diff --git a/lib/fog/aws/credential_fetcher.rb b/lib/fog/aws/credential_fetcher.rb new file mode 100644 index 000000000..fe23625cf --- /dev/null +++ b/lib/fog/aws/credential_fetcher.rb @@ -0,0 +1,63 @@ +require "fog/json" + +module Fog + module AWS + module CredentialFetcher + INSTANCE_METADATA_HOST = "http://169.254.169.254" + INSTANCE_METADATA_PATH = "/latest/meta-data/iam/security-credentials/" + module ServiceMethods + def fetch_credentials(options) + if options[:use_iam_profile] + begin + connection = options[:connection] || Excon.new(INSTANCE_METADATA_HOST) + role_name = connection.get(:path => INSTANCE_METADATA_PATH, :expects => 200).body + role_data = connection.get(:path => INSTANCE_METADATA_PATH+role_name, :expects => 200).body + + session = Fog::JSON.decode(role_data) + credentials = {} + credentials[:aws_access_key_id] = session['AccessKeyId'] + credentials[:aws_secret_access_key] = session['SecretAccessKey'] + credentials[:aws_session_token] = session['Token'] + credentials[:aws_credentials_expire_at] = Time.xmlschema session['Expiration'] + #these indicate the metadata service is unavailable or has no profile setup + credentials + rescue Excon::Errors::Error => e + Fog::Logger.warning("Unable to fetch credentials: #{e.message}") + super + end + else + super + end + end + end + + module ConnectionMethods + def refresh_credentials_if_expired + refresh_credentials if credentials_expired? + end + + private + + def credentials_expired? + @use_iam_profile && + (!@aws_credentials_expire_at || + (@aws_credentials_expire_at && Fog::Time.now > @aws_credentials_expire_at - 15)) #new credentials become available from around 5 minutes before expiration time + end + + def refresh_credentials + if @use_iam_profile + new_credentials = service.fetch_credentials :use_iam_profile => @use_iam_profile + if new_credentials.any? + setup_credentials new_credentials + return true + else + false + end + else + false + end + end + end + end + end +end diff --git a/lib/fog/aws/data_pipeline.rb b/lib/fog/aws/data_pipeline.rb new file mode 100644 index 000000000..821173578 --- /dev/null +++ b/lib/fog/aws/data_pipeline.rb @@ -0,0 +1,126 @@ +require 'fog/aws/core' + +module Fog + module AWS + class DataPipeline < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/data_pipeline' + request :activate_pipeline + request :create_pipeline + request :delete_pipeline + request :describe_pipelines + request :list_pipelines + request :put_pipeline_definition + request :get_pipeline_definition + request :query_objects + request :describe_objects + + model_path 'fog/aws/models/data_pipeline' + model :pipeline + collection :pipelines + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + attr_reader :region + + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to DataPipeline + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # datapipeline = DataPipeline.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'eu-west-1', 'us-east-1' and etc. + # + # ==== Returns + # * DataPipeline object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.data_pipeline' + @connection_options = options[:connection_options] || {} + @version = '2012-10-29' + @region = options[:region] || 'us-east-1' + @host = options[:host] || "datapipeline.#{@region}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + end + + def owner_id + @owner_id ||= security_groups.get('default').owner_id + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new(@aws_access_key_id, @aws_secret_access_key, @region, 'datapipeline') + end + + def request(params) + refresh_credentials_if_expired + + # Params for all DataPipeline requests + params.merge!({ + :expects => 200, + :method => :post, + :path => '/', + }) + + date = Fog::Time.now + params[:headers] = { + 'Date' => date.to_date_header, + 'Host' => @host, + 'X-Amz-Date' => date.to_iso8601_basic, + 'Content-Type' => 'application/x-amz-json-1.1', + 'Content-Length' => params[:body].bytesize.to_s, + }.merge!(params[:headers] || {}) + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params[:headers]['Authorization'] = @signer.sign(params, date) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(params) + end + else + _request(params) + end + end + + def _request(params) + @connection.request(params) + end + end + end + end +end diff --git a/lib/fog/aws/dns.rb b/lib/fog/aws/dns.rb new file mode 100644 index 000000000..6e6650cab --- /dev/null +++ b/lib/fog/aws/dns.rb @@ -0,0 +1,154 @@ +require 'fog/aws/core' + +module Fog + module DNS + class Aws < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :path, :port, :scheme, :version, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + model_path 'fog/aws/models/dns' + model :record + collection :records + model :zone + collection :zones + + request_path 'fog/aws/requests/dns' + request :create_health_check + request :create_hosted_zone + request :delete_health_check + request :get_health_check + request :get_hosted_zone + request :delete_hosted_zone + request :list_health_checks + request :list_hosted_zones + request :change_resource_record_sets + request :list_resource_record_sets + request :get_change + + class Mock + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :buckets => {}, + :limits => { + :duplicate_domains => 5 + }, + :zones => {}, + :changes => {} + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @region = options[:region] + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + + def signature(params) + "foo" + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to Route 53 DNS service + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # dns = Fog::AWS::DNS.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * dns object with connection to aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.dns' + @connection_options = options[:connection_options] || {} + @host = options[:host] || 'route53.amazonaws.com' + @path = options[:path] || '/' + @persistent = options.fetch(:persistent, true) + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @version = options[:version] || '2013-04-01' + + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @hmac = Fog::HMAC.new('sha1', @aws_secret_access_key) + end + + def request(params, &block) + refresh_credentials_if_expired + + params[:headers] ||= {} + params[:headers]['Date'] = Fog::Time.now.to_date_header + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params[:headers]['X-Amzn-Authorization'] = "Aws3-HTTPS AwsAccessKeyId=#{@aws_access_key_id},Algorithm=HmacSHA1,Signature=#{signature(params)}" + params[:path] = "/#{@version}/#{params[:path]}" + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(params, &block) + end + else + _request(params, &block) + end + end + + def _request(params, &block) + @connection.request(params, &block) + end + + def signature(params) + string_to_sign = params[:headers]['Date'] + signed_string = @hmac.sign(string_to_sign) + Base64.encode64(signed_string).chomp! + end + end + end + end +end diff --git a/lib/fog/aws/dynamodb.rb b/lib/fog/aws/dynamodb.rb new file mode 100644 index 000000000..eb9ffd188 --- /dev/null +++ b/lib/fog/aws/dynamodb.rb @@ -0,0 +1,152 @@ +require 'fog/aws/core' + +module Fog + module AWS + class DynamoDB < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :aws_session_token, :host, :path, :port, :scheme, :persistent, :region, :use_iam_profile, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/dynamodb' + request :batch_get_item + request :batch_write_item + request :create_table + request :delete_item + request :delete_table + request :describe_table + request :get_item + request :list_tables + request :put_item + request :query + request :scan + request :update_item + request :update_table + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :domains => {} + } + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + end + + def data + self.class.data[@aws_access_key_id] + end + + def reset_data + self.class.data.delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to DynamoDB + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # ddb = DynamoDB.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * DynamoDB object with connection to aws + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @region = options[:region] || 'us-east-1' + + setup_credentials(options) + + @connection_options = options[:connection_options] || {} + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.dynamodb' + + @host = options[:host] || "dynamodb.#{@region}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || '443' + @scheme = options[:scheme] || 'https' + + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new(@aws_access_key_id, @aws_secret_access_key, @region, 'dynamodb') + end + + def reload + @connection.reset + end + + def request(params) + refresh_credentials_if_expired + + # defaults for all dynamodb requests + params.merge!({ + :expects => 200, + :method => :post, + :path => '/' + }) + + # setup headers and sign with signature v4 + date = Fog::Time.now + params[:headers] = { + 'Content-Type' => 'application/x-amz-json-1.0', + 'Date' => date.to_iso8601_basic, + 'Host' => @host, + }.merge!(params[:headers]) + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params[:headers]['Authorization'] = @signer.sign(params, date) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(params) + end + else + _request(params) + end + end + + def _request(params) + response = @connection.request(params) + + unless response.body.empty? + response.body = Fog::JSON.decode(response.body) + end + + response + end + + end + end + end +end diff --git a/lib/fog/aws/elasticache.rb b/lib/fog/aws/elasticache.rb new file mode 100644 index 000000000..c5f7cd085 --- /dev/null +++ b/lib/fog/aws/elasticache.rb @@ -0,0 +1,216 @@ +require 'fog/aws/core' + +module Fog + module AWS + class Elasticache < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class IdentifierTaken < Fog::Errors::Error; end + class InvalidInstance < Fog::Errors::Error; end + class AuthorizationAlreadyExists < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/elasticache' + + request :create_cache_cluster + request :delete_cache_cluster + request :describe_cache_clusters + request :modify_cache_cluster + request :reboot_cache_cluster + + request :create_cache_parameter_group + request :delete_cache_parameter_group + request :describe_cache_parameter_groups + request :modify_cache_parameter_group + request :reset_cache_parameter_group + request :describe_engine_default_parameters + request :describe_cache_parameters + request :describe_reserved_cache_nodes + + request :create_cache_security_group + request :delete_cache_security_group + request :describe_cache_security_groups + request :authorize_cache_security_group_ingress + request :revoke_cache_security_group_ingress + + request :create_cache_subnet_group + request :describe_cache_subnet_groups + request :delete_cache_subnet_group + + request :describe_events + + model_path 'fog/aws/models/elasticache' + model :cluster + collection :clusters + model :security_group + collection :security_groups + model :parameter_group + collection :parameter_groups + model :subnet_group + collection :subnet_groups + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.elasticache' + options[:region] ||= 'us-east-1' + + @region = options[:region] + @host = options[:host] || "elasticache.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new( + "#{@scheme}://#{@host}:#{@port}#{@path}", options[:persistent] + ) + + setup_credentials(options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'elasticache') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :signer => @signer, + :aws_session_token => @aws_session_token, + :method => 'POST', + :host => @host, + :path => @path, + :port => @port, + :version => '2013-06-15' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'CacheSecurityGroupNotFound', 'CacheParameterGroupNotFound', 'CacheClusterNotFound' + Fog::AWS::Elasticache::NotFound.slurp(error, match[:message]) + when 'CacheSecurityGroupAlreadyExists' + Fog::AWS::Elasticache::IdentifierTaken.slurp(error, match[:message]) + when 'InvalidParameterValue' + Fog::AWS::Elasticache::InvalidInstance.slurp(error, match[:message]) + else + Fog::AWS::Elasticache::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + + class Mock + include Fog::AWS::CredentialFetcher::ConnectionMethods + + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :clusters => {}, # cache cluster data, indexed by cluster ID + :security_groups => {}, # security groups + :subnet_groups => {}, + :parameter_groups => {"default.memcached1.4" => { "CacheParameterGroupFamily"=>"memcached1.4", + "Description"=>"Default parameter group for memcached1.4", + "CacheParameterGroupName"=>"default.memcached1.4" + }, + "default.redis2.6" => {"CacheParameterGroupFamily"=>"redis2.6", + "Description"=>"Default parameter group for redis2.6", + "CacheParameterGroupName"=>"default.redis2.6" + } + } + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @aws_credentials_expire_at = Time::now + 20 + setup_credentials(options) + @region = options[:region] || 'us-east-1' + unless ['ap-northeast-1', 'ap-southeast-1', 'eu-west-1', 'us-east-1', + 'us-west-1', 'us-west-2', 'sa-east-1'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def region_data + self.class.data[@region] + end + + def data + self.region_data[@aws_access_key_id] + end + + def reset_data + self.region_data.delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + + # returns an Array of (Mock) elasticache nodes, representated as Hashes + def create_cache_nodes(cluster_id, num_nodes = 1, port = '11211') + (1..num_nodes).map do |node_number| + node_id = "%04d" % node_number + { # each hash represents a cache cluster node + "CacheNodeId" => node_id, + "Port" => port, + "ParameterGroupStatus" => "in-sync", + "CacheNodeStatus" => "available", + "CacheNodeCreateTime" => Time.now.utc.to_s, + "Address" => + "#{cluster_id}.#{node_id}.use1.cache.amazonaws.com" + } + end + end + end + end + end +end diff --git a/lib/fog/aws/elb.rb b/lib/fog/aws/elb.rb new file mode 100644 index 000000000..211de950d --- /dev/null +++ b/lib/fog/aws/elb.rb @@ -0,0 +1,240 @@ +require 'fog/aws/core' + +module Fog + module AWS + class ELB < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class DuplicatePolicyName < Fog::Errors::Error; end + class IdentifierTaken < Fog::Errors::Error; end + class InvalidInstance < Fog::Errors::Error; end + class InvalidConfigurationRequest < Fog::Errors::Error; end + class PolicyNotFound < Fog::Errors::Error; end + class PolicyTypeNotFound < Fog::Errors::Error; end + class Throttled < Fog::Errors::Error; end + class TooManyPolicies < Fog::Errors::Error; end + class ValidationError < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/elb' + request :configure_health_check + request :create_app_cookie_stickiness_policy + request :create_lb_cookie_stickiness_policy + request :create_load_balancer + request :create_load_balancer_listeners + request :create_load_balancer_policy + request :delete_load_balancer + request :delete_load_balancer_listeners + request :delete_load_balancer_policy + request :deregister_instances_from_load_balancer + request :describe_instance_health + request :describe_load_balancers + request :describe_load_balancer_attributes + request :describe_load_balancer_policies + request :describe_load_balancer_policy_types + request :disable_availability_zones_for_load_balancer + request :enable_availability_zones_for_load_balancer + request :modify_load_balancer_attributes + request :register_instances_with_load_balancer + request :set_load_balancer_listener_ssl_certificate + request :set_load_balancer_policies_of_listener + request :attach_load_balancer_to_subnets + request :detach_load_balancer_from_subnets + request :apply_security_groups_to_load_balancer + request :set_load_balancer_policies_for_backend_server + request :add_tags + request :describe_tags + request :remove_tags + + model_path 'fog/aws/models/elb' + model :load_balancer + collection :load_balancers + model :policy + collection :policies + model :listener + collection :listeners + model :backend_server_description + collection :backend_server_descriptions + + class Mock + require 'fog/aws/elb/policy_types' + + def self.data + @data ||= Hash.new do |hash, region| + owner_id = Fog::AWS::Mock.owner_id + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :owner_id => owner_id, + :load_balancers => {}, + :policy_types => Fog::AWS::ELB::Mock::POLICY_TYPES + } + end + end + end + + def self.dns_name(name, region) + "#{name}-#{Fog::Mock.random_hex(8)}.#{region}.elb.amazonaws.com" + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + + @region = options[:region] || 'us-east-1' + setup_credentials(options) + + unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'elasticloadbalancing') + + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to ELB + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # elb = ELB.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'eu-west-1', 'us-east-1', etc. + # + # ==== Returns + # * ELB object with connection to Aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + @connection_options = options[:connection_options] || {} + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.elb' + + options[:region] ||= 'us-east-1' + @region = options[:region] + @host = options[:host] || "elasticloadbalancing.#{@region}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options={}) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'elasticloadbalancing') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :aws_session_token => @aws_session_token, + :signer => @signer, + :host => @host, + :path => @path, + :port => @port, + :version => '2012-06-01', + :method => 'POST' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'CertificateNotFound' + Fog::AWS::IAM::NotFound.slurp(error, match[:message]) + when 'DuplicateLoadBalancerName' + Fog::AWS::ELB::IdentifierTaken.slurp(error, match[:message]) + when 'DuplicatePolicyName' + Fog::AWS::ELB::DuplicatePolicyName.slurp(error, match[:message]) + when 'InvalidInstance' + Fog::AWS::ELB::InvalidInstance.slurp(error, match[:message]) + when 'InvalidConfigurationRequest' + # when do they fucking use this shit? + Fog::AWS::ELB::InvalidConfigurationRequest.slurp(error, match[:message]) + when 'LoadBalancerNotFound' + Fog::AWS::ELB::NotFound.slurp(error, match[:message]) + when 'PolicyNotFound' + Fog::AWS::ELB::PolicyNotFound.slurp(error, match[:message]) + when 'PolicyTypeNotFound' + Fog::AWS::ELB::PolicyTypeNotFound.slurp(error, match[:message]) + when 'Throttling' + Fog::AWS::ELB::Throttled.slurp(error, match[:message]) + when 'TooManyPolicies' + Fog::AWS::ELB::TooManyPolicies.slurp(error, match[:message]) + when 'ValidationError' + Fog::AWS::ELB::ValidationError.slurp(error, match[:message]) + else + Fog::AWS::ELB::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/elb/policy_types.rb b/lib/fog/aws/elb/policy_types.rb new file mode 100644 index 000000000..280e9ea12 --- /dev/null +++ b/lib/fog/aws/elb/policy_types.rb @@ -0,0 +1,477 @@ +class Fog::AWS::ELB::Mock + POLICY_TYPES = [{ + "Description" => "", + "PolicyAttributeTypeDescriptions" => [{ + "AttributeName"=>"CookieName", + "AttributeType"=>"String", + "Cardinality"=>"ONE", + "DefaultValue"=>"", + "Description"=>"" + }], + "PolicyTypeName"=>"AppCookieStickinessPolicyType" + }, + { + "Description" => "", + "PolicyAttributeTypeDescriptions" => [{ + "AttributeName"=>"CookieExpirationPeriod", + "AttributeType"=>"String", + "Cardinality"=>"ONE", + "DefaultValue"=>"", + "Description"=>"" + }], + "PolicyTypeName"=>"LBCookieStickinessPolicyType" + }, + { + "Description" => "Policy containing a list of public keys to accept when authenticating the back-end server(s). This policy cannot be applied directly to back-end servers or listeners but must be part of a BackendServerAuthenticationPolicyType.", + "PolicyAttributeTypeDescriptions" => [{ + "AttributeName"=>"PublicKey", + "AttributeType"=>"String", + "Cardinality"=>"ONE", + "DefaultValue"=>"", + "Description"=>"" + }], + "PolicyTypeName"=>"PublicKeyPolicyType" + }, + { + "Description" => "Listener policy that defines the ciphers and protocols that will be accepted by the load balancer. This policy can be associated only with HTTPS/SSL listeners.", + "PolicyAttributeTypeDescriptions" => [{ + "AttributeName"=>"Protocol-SSLv2", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EDH-DSS-DES-CBC3-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-RSA-CAMELLIA128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DES-CBC-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"KRB5-RC4-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-CAMELLIA128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-KRB5-RC4-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-RC4-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"PSK-RC4-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"PSK-AES128-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-EDH-RSA-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"CAMELLIA128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-DSS-AES128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EDH-RSA-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-RSA-SEED-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"KRB5-DES-CBC-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-RSA-CAMELLIA256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-DES-CBC3-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DES-CBC3-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-KRB5-RC2-CBC-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EDH-DSS-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"KRB5-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"PSK-AES256-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-AES256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"KRB5-DES-CBC3-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"AES128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-DSS-SEED-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-CAMELLIA256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-KRB5-RC4-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EDH-RSA-DES-CBC3-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-KRB5-DES-CBC-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"Protocol-TLSv1", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"PSK-3DES-EDE-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"SEED-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-DSS-CAMELLIA256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"IDEA-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"RC2-CBC-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"KRB5-RC4-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-AES128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"RC4-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"AES256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"Protocol-SSLv3", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DES-CBC3-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-RSA-AES128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-EDH-DSS-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-KRB5-RC2-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-RSA-AES256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"KRB5-DES-CBC3-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"RC4-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"TRUE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-RC2-CBC-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-ADH-RC4-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-RC4-MD5", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"CAMELLIA256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-DSS-CAMELLIA128-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-KRB5-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"EXP-ADH-DES-CBC-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"DHE-DSS-AES256-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }, + { + "AttributeName"=>"ADH-SEED-SHA", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"FALSE", + "Description"=>"" + }], + "PolicyTypeName"=>"SSLNegotiationPolicyType" + }, + { + "Description"=>"Policy that controls whether to include the IP address and port of the originating request for TCP messages. This policy operates on TCP/SSL listeners only", + "PolicyAttributeTypeDescriptions"=>[{ + "AttributeName"=>"ProxyProtocol", + "AttributeType"=>"Boolean", + "Cardinality"=>"ONE", + "DefaultValue"=>"", + "Description"=>"" + }], + "PolicyTypeName"=>"ProxyProtocolPolicyType" +}] +end diff --git a/lib/fog/aws/emr.rb b/lib/fog/aws/emr.rb new file mode 100644 index 000000000..a4d996978 --- /dev/null +++ b/lib/fog/aws/emr.rb @@ -0,0 +1,139 @@ +require 'fog/aws/core' + +module Fog + module AWS + class EMR < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class IdentifierTaken < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/emr' + + request :add_instance_groups + request :add_job_flow_steps + request :describe_job_flows + request :modify_instance_groups + request :run_job_flow + request :set_termination_protection + request :terminate_job_flows + + # model_path 'fog/aws/models/rds' + # model :server + # collection :servers + # model :snapshot + # collection :snapshots + # model :parameter_group + # collection :parameter_groups + # + # model :parameter + # collection :parameters + # + # model :security_group + # collection :security_groups + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to EMR + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # emr = EMR.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, in 'eu-west-1', 'us-east-1' and etc. + # + # ==== Returns + # * EMR object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @connection_options = options[:connection_options] || {} + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.emr' + + options[:region] ||= 'us-east-1' + @host = options[:host] || "elasticmapreduce.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + @region = options[:region] + setup_credentials(options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'elasticmapreduce') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :signer => @signer, + :aws_session_token => @aws_session_token, + :method => 'POST', + :host => @host, + :path => @path, + :port => @port, + :version => '2009-03-31' #'2010-07-28' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + end + + end + end + end +end diff --git a/lib/fog/aws/glacier.rb b/lib/fog/aws/glacier.rb new file mode 100644 index 000000000..afe99ed02 --- /dev/null +++ b/lib/fog/aws/glacier.rb @@ -0,0 +1,179 @@ +require 'fog/aws/core' + +module Fog + module AWS + class Glacier < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/glacier' + + request :abort_multipart_upload + request :complete_multipart_upload + request :create_archive + request :create_vault + request :delete_archive + request :delete_vault + request :delete_vault_notification_configuration + request :describe_job + request :describe_vault + request :get_job_output + request :get_vault_notification_configuration + request :initiate_job + request :initiate_multipart_upload + request :list_jobs + request :list_multipart_uploads + request :list_parts + request :list_vaults + request :set_vault_notification_configuration + request :upload_part + + model_path 'fog/aws/models/glacier' + model :vault + collection :vaults + + MEGABYTE = 1024*1024 + + class TreeHash + def self.digest(body) + new.add_part(body) + end + + def reduce_digests(digests) + while digests.length > 1 + digests = digests.each_slice(2).map do |pair| + if pair.length == 2 + Digest::SHA256.digest(pair[0]+pair[1]) + else + pair.first + end + end + end + digests.first + end + + def initialize + @digests = [] + end + + def add_part(bytes) + part = self.digest_for_part(bytes) + @digests << part + part.unpack('H*').first + end + + def digest_for_part(body) + chunk_count = [body.bytesize / MEGABYTE + (body.bytesize % MEGABYTE > 0 ? 1 : 0), 1].max + if body.respond_to? :byteslice + digests_for_part = chunk_count.times.map {|chunk_index| Digest::SHA256.digest(body.byteslice(chunk_index * MEGABYTE, MEGABYTE))} + else + if body.respond_to? :encoding + old_encoding = body.encoding + body.force_encoding('BINARY') + end + digests_for_part = chunk_count.times.map {|chunk_index| Digest::SHA256.digest(body.slice(chunk_index * MEGABYTE, MEGABYTE))} + if body.respond_to? :encoding + body.force_encoding(old_encoding) + end + end + reduce_digests(digests_for_part) + end + + def hexdigest + digest.unpack('H*').first + end + + def digest + reduce_digests(@digests) + end + end + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to Glacier + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # ses = SES.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'us-east-1' and etc. + # + # ==== Returns + # * Glacier object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @region = options[:region] || 'us-east-1' + + setup_credentials(options) + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.glacier' + @connection_options = options[:connection_options] || {} + @host = options[:host] || "glacier.#{@region}.amazonaws.com" + @version = '2012-06-01' + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + private + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'glacier') + end + + def request(params, &block) + refresh_credentials_if_expired + + date = Fog::Time.now + params[:headers]['Date'] = date.to_date_header + params[:headers]['x-amz-date'] = date.to_iso8601_basic + + params[:headers]['Host'] = @host + params[:headers]['x-amz-glacier-version'] = @version + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params[:headers]['Authorization'] = @signer.sign params, date + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(params, &block) + end + else + _request(params, &block) + end + end + + def _request(params, &block) + response = @connection.request(params, &block) + if response.headers['Content-Type'] == 'application/json' && response.body.size > 0 #body will be empty if the streaming form has been used + response.body = Fog::JSON.decode(response.body) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/iam.rb b/lib/fog/aws/iam.rb new file mode 100644 index 000000000..8bb26efb3 --- /dev/null +++ b/lib/fog/aws/iam.rb @@ -0,0 +1,260 @@ +require 'fog/aws/core' + +module Fog + module AWS + class IAM < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class EntityAlreadyExists < Fog::AWS::IAM::Error; end + class KeyPairMismatch < Fog::AWS::IAM::Error; end + class LimitExceeded < Fog::AWS::IAM::Error; end + class MalformedCertificate < Fog::AWS::IAM::Error; end + class ValidationError < Fog::AWS::IAM::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :path, :port, :scheme, :persistent, :instrumentor, :instrumentor_name, :aws_session_token, :use_iam_profile, :aws_credentials_expire_at + + request_path 'fog/aws/requests/iam' + request :add_user_to_group + request :add_role_to_instance_profile + request :create_access_key + request :create_account_alias + request :create_group + request :create_instance_profile + request :create_login_profile + request :create_role + request :create_user + request :delete_access_key + request :delete_account_password_policy + request :delete_account_alias + request :delete_group + request :delete_group_policy + request :delete_instance_profile + request :delete_login_profile + request :delete_role + request :delete_role_policy + request :delete_server_certificate + request :delete_signing_certificate + request :delete_user + request :delete_user_policy + request :get_account_summary + request :get_account_password_policy + request :get_group + request :get_group_policy + request :get_instance_profile + request :get_role_policy + request :get_login_profile + request :get_server_certificate + request :get_role + request :get_user + request :get_user_policy + request :list_access_keys + request :list_account_aliases + request :list_group_policies + request :list_groups + request :list_groups_for_user + request :list_instance_profiles + request :list_instance_profiles_for_role + request :list_mfa_devices + request :list_roles + request :list_role_policies + request :list_server_certificates + request :list_signing_certificates + request :list_user_policies + request :list_users + request :put_group_policy + request :put_role_policy + request :put_user_policy + request :remove_role_from_instance_profile + request :remove_user_from_group + request :update_access_key + request :update_group + request :update_login_profile + request :update_account_password_policy + request :update_server_certificate + request :update_signing_certificate + request :update_user + request :upload_server_certificate + request :upload_signing_certificate + + model_path 'fog/aws/models/iam' + model :user + collection :users + model :policy + collection :policies + model :access_key + collection :access_keys + model :role + collection :roles + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :owner_id => Fog::AWS::Mock.owner_id, + :server_certificates => {}, + :access_keys => [{ + "Status" => "Active", + "AccessKeyId" => key + }], + :devices => [{ + :enable_date => Time.now, + :serial_number => 'R1234', + :user_name => 'Bob' + }], + :users => Hash.new do |uhash, ukey| + uhash[ukey] = { + :user_id => Fog::AWS::Mock.key_id, + :path => '/', + :arn => "arn:aws:iam::#{Fog::AWS::Mock.owner_id}:user/#{ukey}", + :access_keys => [], + :created_at => Time.now, + :policies => {} + } + end, + :groups => Hash.new do |ghash, gkey| + ghash[gkey] = { + :group_id => Fog::AWS::Mock.key_id, + :arn => "arn:aws:iam::#{Fog::AWS::Mock.owner_id}:group/#{gkey}", + :members => [], + :created_at => Time.now, + :policies => {} + } + end + } + end + end + + def self.reset + @data = nil + end + + def self.server_certificate_id + Fog::Mock.random_hex(16) + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @aws_credentials_expire_at = Time::now + 20 + setup_credentials(options) + end + + def data + self.class.data[@aws_access_key_id] + end + + def reset_data + self.class.data.delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + + # Initialize connection to IAM + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # iam = IAM.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * IAM object with connection to Aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + @connection_options = options[:connection_options] || {} + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.iam' + @host = options[:host] || 'iam.amazonaws.com' + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + #global services that have no region are signed with the us-east-1 region + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,'us-east-1','iam') + end + + def request(params) + refresh_credentials_if_expired + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :signer => @signer, + :aws_session_token => @aws_session_token, + :host => @host, + :path => @path, + :port => @port, + :version => '2010-05-08', + :method => 'POST' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :idempotent => idempotent, + :headers => headers, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'CertificateNotFound', 'NoSuchEntity' + Fog::AWS::IAM::NotFound.slurp(error, match[:message]) + when 'EntityAlreadyExists', 'KeyPairMismatch', 'LimitExceeded', 'MalformedCertificate', 'ValidationError' + Fog::AWS::IAM.const_get(match[:code]).slurp(error, match[:message]) + else + Fog::AWS::IAM::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/activities.rb b/lib/fog/aws/models/auto_scaling/activities.rb new file mode 100644 index 000000000..a99da5b0d --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/activities.rb @@ -0,0 +1,37 @@ +require 'fog/aws/models/auto_scaling/activity' + +module Fog + module AWS + class AutoScaling + class Activities < Fog::Collection + model Fog::AWS::AutoScaling::Activity + + attribute :filters + + # Creates a new scaling policy. + def initialize(attributes={}) + self.filters = attributes + super(attributes) + end + + def all(filters_arg = filters) + data = [] + next_token = nil + filters = filters_arg + loop do + result = service.describe_scaling_activities(filters.merge('NextToken' => next_token)).body['DescribeScalingActivitiesResult'] + data += result['Activities'] + next_token = result['NextToken'] + break if next_token.nil? + end + load(data) + end + + def get(identity) + data = service.describe_scaling_activities('ActivityId' => identity).body['DescribeScalingActivitiesResult']['Activities'].first + new(data) unless data.nil? + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/activity.rb b/lib/fog/aws/models/auto_scaling/activity.rb new file mode 100644 index 000000000..032f4e6fb --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/activity.rb @@ -0,0 +1,27 @@ +require 'fog/core/model' + +module Fog + module AWS + class AutoScaling + class Activity < Fog::Model + identity :id, :aliases => 'ActivityId' + attribute :auto_scaling_group_name, :aliases => 'AutoScalingGroupName' + attribute :cause, :aliases => 'Cause' + attribute :description, :aliases => 'Description' + attribute :end_time, :aliases => 'EndTime' + attribute :progress, :aliases => 'Progress' + attribute :start_time, :aliases => 'StartTime' + attribute :status_code, :aliases => 'StatusCode' + attribute :status_message, :aliases => 'StatusMessage' + + def group + service.groups.get(attributes['AutoScalingGroupName']) + end + + def save + raise "Operation not supported" + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/configuration.rb b/lib/fog/aws/models/auto_scaling/configuration.rb new file mode 100644 index 000000000..2cef19ce9 --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/configuration.rb @@ -0,0 +1,69 @@ +require 'fog/core/model' + +module Fog + module AWS + class AutoScaling + class Configuration < Fog::Model + identity :id, :aliases => 'LaunchConfigurationName' + attribute :arn, :aliases => 'LaunchConfigurationARN' + attribute :associate_public_ip, :aliases => 'AssociatePublicIpAddress' + attribute :block_device_mappings, :aliases => 'BlockDeviceMappings' + attribute :created_at, :aliases => 'CreatedTime' + attribute :ebs_optimized, :aliases => 'EbsOptimized' + attribute :iam_instance_profile, :aliases => 'IamInstanceProfile' + attribute :image_id, :aliases => 'ImageId' + #attribute :instance_monitoring, :aliases => 'InstanceMonitoring' + attribute :instance_monitoring, :aliases => 'InstanceMonitoring', :squash => 'Enabled' + attribute :instance_type, :aliases => 'InstanceType' + attribute :kernel_id, :aliases => 'KernelId' + attribute :key_name, :aliases => 'KeyName' + attribute :ramdisk_id, :aliases => 'RamdiskId' + attribute :security_groups, :aliases => 'SecurityGroups' + attribute :user_data, :aliases => 'UserData' + attribute :spot_price, :aliases => 'SpotPrice' + attribute :placement_tenancy, :aliases => 'PlacementTenancy' + + + def initialize(attributes={}) + #attributes[:availability_zones] ||= %w(us-east-1a us-east-1b us-east-1c us-east-1d) + #attributes['ListenerDescriptions'] ||= [{ + # 'Listener' => {'LoadBalancerPort' => 80, 'InstancePort' => 80, 'Protocol' => 'http'}, + # 'PolicyNames' => [] + #}] + #attributes['Policies'] ||= {'AppCookieStickinessPolicies' => [], 'LBCookieStickinessPolicies' => []} + super + end + + def ready? + # AutoScaling requests are synchronous + true + end + + def save + requires :id + requires :image_id + requires :instance_type + + options = Hash[self.class.aliases.map { |key, value| [key, send(value)] }] + options.delete_if { |key, value| value.nil? } + service.create_launch_configuration(image_id, instance_type, id, options) #, listeners.map{|l| l.to_params}) + + # reload instead of merge attributes b/c some attrs (like HealthCheck) + # may be set, but only the DNS name is returned in the create_load_balance + # API call + reload + end + + def reload + super + self + end + + def destroy + requires :id + service.delete_launch_configuration(id) + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/configurations.rb b/lib/fog/aws/models/auto_scaling/configurations.rb new file mode 100644 index 000000000..a62c6e9a8 --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/configurations.rb @@ -0,0 +1,33 @@ +require 'fog/aws/models/auto_scaling/configuration' + +module Fog + module AWS + class AutoScaling + class Configurations < Fog::Collection + model Fog::AWS::AutoScaling::Configuration + + # Creates a new launch configuration + def initialize(attributes={}) + super + end + + def all + data = [] + next_token = nil + loop do + result = service.describe_launch_configurations('NextToken' => next_token).body['DescribeLaunchConfigurationsResult'] + data += result['LaunchConfigurations'] + next_token = result['NextToken'] + break if next_token.nil? + end + load(data) + end + + def get(identity) + data = service.describe_launch_configurations('LaunchConfigurationNames' => identity).body['DescribeLaunchConfigurationsResult']['LaunchConfigurations'].first + new(data) unless data.nil? + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/group.rb b/lib/fog/aws/models/auto_scaling/group.rb new file mode 100644 index 000000000..c796b95f7 --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/group.rb @@ -0,0 +1,150 @@ +require 'fog/core/model' + +module Fog + module AWS + class AutoScaling + class Group < Fog::Model + identity :id, :aliases => 'AutoScalingGroupName' + attribute :arn, :aliases => 'AutoScalingGroupARN' + attribute :availability_zones, :aliases => 'AvailabilityZones' + attribute :created_at, :aliases => 'CreatedTime' + attribute :default_cooldown, :aliases => 'DefaultCooldown' + attribute :desired_capacity, :aliases => 'DesiredCapacity' + attribute :enabled_metrics, :aliases => 'EnabledMetrics' + attribute :health_check_grace_period, :aliases => 'HealthCheckGracePeriod' + attribute :health_check_type, :aliases => 'HealthCheckType' + attribute :instances, :aliases => 'Instances' + attribute :launch_configuration_name, :aliases => 'LaunchConfigurationName' + attribute :load_balancer_names, :aliases => 'LoadBalancerNames' + attribute :max_size, :aliases => 'MaxSize' + attribute :min_size, :aliases => 'MinSize' + attribute :placement_group, :aliases => 'PlacementGroup' + attribute :suspended_processes, :aliases => 'SuspendedProcesses' + attribute :tags, :aliases => 'Tags' + attribute :termination_policies, :aliases => 'TerminationPolicies' + attribute :vpc_zone_identifier, :aliases => 'VPCZoneIdentifier' + + def initialize(attributes={}) + self.instances = [] + self.default_cooldown = 300 + self.desired_capacity = 0 + self.enabled_metrics = [] + self.health_check_grace_period = 0 + self.health_check_type = 'EC2' + self.load_balancer_names = [] + self.max_size = 0 + self.min_size = 0 + self.suspended_processes = [] + self.tags = {} + self.termination_policies = ['Default'] + super + end + + def activities + requires :id + data = [] + next_token = nil + loop do + result = service.describe_scaling_activities('AutoScalingGroupName' => id, 'NextToken' => next_token).body['DescribeScalingActivitiesResult'] + data += result['Activities'] + next_token = result['NextToken'] + break if next_token.nil? + end + Fog::AWS::AutoScaling::Activities.new({ + :data => data, + :service => service, + #:load_balancer => self + }) + end + + def configuration + requires :launch_configuration_name + service.configurations.get(launch_configuration_name) + end + + def disable_metrics_collection(metrics = {}) + requires :id + service.disable_metrics_collection(id, 'Metrics' => metrics) + reload + end + + def enable_metrics_collection(granularity = '1Minute', metrics = {}) + requires :id + service.enable_metrics_collection(id, granularity, 'Metrics' => metrics) + reload + end + + def instances + Fog::AWS::AutoScaling::Instances.new(:service => service).load(attributes[:instances]) + end + + def instances_in_service + attributes[:instances].select {|hash| hash['LifecycleState'] == 'InService'}.map {|hash| hash['InstanceId']} + end + + def instances_out_service + attributes[:instances].select {|hash| hash['LifecycleState'] == 'OutOfService'}.map {|hash| hash['InstanceId']} + end + + def resume_processes(processes = []) + requires :id + service.resume_processes(id, 'ScalingProcesses' => processes) + reload + end + + def suspend_processes(processes = []) + requires :id + service.suspend_processes(id, 'ScalingProcesses' => processes) + reload + end + + def ready? + # Is this useful? + #instances_in_service.length == desired_capacity + #instances_in_service.length >= min_size + true + end + + def save + requires :id + requires :availability_zones + requires :launch_configuration_name + requires :max_size + requires :min_size + service.create_auto_scaling_group(id, availability_zones, launch_configuration_name, max_size, min_size, filtered_options(:create_auto_scaling_group)) + reload + end + + #def reload + # super + # self + #end + + def destroy(options = { :force => false }) + requires :id + + opts = {} + opts.merge!({'ForceDelete' => true}) if options[:force] + + service.delete_auto_scaling_group(id, opts) + end + + def update + requires :id + service.update_auto_scaling_group(id, filtered_options(:update_auto_scaling_group) ) + reload + end + + def filtered_options(method) + Hash[options.select{|k,_| ExpectedOptions[method].include?(k)}] + end + + def options + ret = Hash[self.class.aliases.map { |key, value| [key, send(value)] }] + ret.delete_if { |key, value| value.nil? } + ret + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/groups.rb b/lib/fog/aws/models/auto_scaling/groups.rb new file mode 100644 index 000000000..013c1988c --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/groups.rb @@ -0,0 +1,37 @@ +require 'fog/aws/models/auto_scaling/group' + +module Fog + module AWS + class AutoScaling + class Groups < Fog::Collection + model Fog::AWS::AutoScaling::Group + + attribute :filters + + # Creates a new auto scaling group. + def initialize(attributes={}) + self.filters = attributes + super + end + + def all(filters_arg = filters) + data = [] + next_token = nil + filters = filters_arg + loop do + result = service.describe_auto_scaling_groups(filters.merge('NextToken' => next_token)).body['DescribeAutoScalingGroupsResult'] + data += result['AutoScalingGroups'] + next_token = result['NextToken'] + break if next_token.nil? + end + load(data) + end + + def get(identity) + data = service.describe_auto_scaling_groups('AutoScalingGroupNames' => identity).body['DescribeAutoScalingGroupsResult']['AutoScalingGroups'].first + new(data) unless data.nil? + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/instance.rb b/lib/fog/aws/models/auto_scaling/instance.rb new file mode 100644 index 000000000..8e05ac8eb --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/instance.rb @@ -0,0 +1,58 @@ +require 'fog/core/model' + +module Fog + module AWS + class AutoScaling + class Instance < Fog::Model + identity :id, :aliases => 'InstanceId' + attribute :auto_scaling_group_name, :aliases => 'AutoScalingGroupName' + attribute :availability_zone, :aliases => 'AvailabilityZone' + attribute :health_status, :aliases => 'HealthStatus' + attribute :launch_configuration_name, :aliases => 'LaunchConfigurationName' + attribute :life_cycle_state, :aliases => 'LifecycleState' + + def initialize(attributes={}) + super + end + + def group + service.groups.get(attributes['AutoScalingGroupName']) + end + + def configuration + service.configurations.get(attributes['LaunchConfigurationName']) + end + + def set_health(health_status, options) + requires :id + service.set_instance_health(health_status, id, options) + reload + end + + def terminate(should_decrement_desired_capacity) + requires :id + service.terminate_instance_in_auto_scaling_group(id, should_decrement_desired_capacity) + reload + end + + def healthy? + health_status == 'Healthy' + end + + def ready? + life_cycle_state == 'InService' + end + + def reload + super + self + end + + #def destroy + # requires :id + # service.delete_auto_scaling_group(id) + #end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/instances.rb b/lib/fog/aws/models/auto_scaling/instances.rb new file mode 100644 index 000000000..c04765e70 --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/instances.rb @@ -0,0 +1,28 @@ +require 'fog/aws/models/auto_scaling/instance' + +module Fog + module AWS + class AutoScaling + class Instances < Fog::Collection + model Fog::AWS::AutoScaling::Instance + + def all + data = [] + next_token = nil + loop do + result = service.describe_auto_scaling_instances('NextToken' => next_token).body['DescribeAutoScalingInstancesResult'] + data += result['AutoScalingInstances'] + next_token = result['NextToken'] + break if next_token.nil? + end + load(data) + end + + def get(identity) + data = service.describe_auto_scaling_instances('InstanceIds' => identity).body['DescribeAutoScalingInstancesResult']['AutoScalingInstances'].first + new(data) unless data.nil? + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/policies.rb b/lib/fog/aws/models/auto_scaling/policies.rb new file mode 100644 index 000000000..78c0c9d4f --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/policies.rb @@ -0,0 +1,37 @@ +require 'fog/aws/models/auto_scaling/policy' + +module Fog + module AWS + class AutoScaling + class Policies < Fog::Collection + model Fog::AWS::AutoScaling::Policy + + attribute :filters + + # Creates a new scaling policy. + def initialize(attributes={}) + self.filters = attributes + super(attributes) + end + + def all(filters_arg = filters) + data = [] + next_token = nil + self.filters = filters_arg + loop do + result = service.describe_policies(filters.merge('NextToken' => next_token)).body['DescribePoliciesResult'] + data += result['ScalingPolicies'] + next_token = result['NextToken'] + break if next_token.nil? + end + load(data) + end + + def get(identity, auto_scaling_group = nil) + data = service.describe_policies('PolicyNames' => identity, 'AutoScalingGroupName' => auto_scaling_group).body['DescribePoliciesResult']['ScalingPolicies'].first + new(data) unless data.nil? + end + end + end + end +end diff --git a/lib/fog/aws/models/auto_scaling/policy.rb b/lib/fog/aws/models/auto_scaling/policy.rb new file mode 100644 index 000000000..780eb71de --- /dev/null +++ b/lib/fog/aws/models/auto_scaling/policy.rb @@ -0,0 +1,46 @@ +require 'fog/core/model' + +module Fog + module AWS + class AutoScaling + class Policy < Fog::Model + identity :id, :aliases => 'PolicyName' + attribute :arn, :aliases => 'PolicyARN' + attribute :adjustment_type, :aliases => 'AdjustmentType' + attribute :alarms, :aliases => 'Alarms' + attribute :auto_scaling_group_name, :aliases => 'AutoScalingGroupName' + attribute :cooldown, :aliases => 'Cooldown' + attribute :min_adjustment_step, :aliases => 'MinAdjustmentStep' + attribute :scaling_adjustment, :aliases => 'ScalingAdjustment' + + def initialize(attributes) + attributes['AdjustmentType'] ||= 'ChangeInCapacity' + attributes['ScalingAdjustment'] ||= 1 + super + end + + # TODO: implement #alarms + # TODO: implement #auto_scaling_group + + def save + requires :id + requires :adjustment_type + requires :auto_scaling_group_name + requires :scaling_adjustment + + options = Hash[self.class.aliases.map { |key, value| [key, send(value)] }] + options.delete_if { |key, value| value.nil? } + + service.put_scaling_policy(adjustment_type, auto_scaling_group_name, id, scaling_adjustment, options) + reload + end + + def destroy + requires :id + requires :auto_scaling_group_name + service.delete_policy(auto_scaling_group_name, id) + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/application.rb b/lib/fog/aws/models/beanstalk/application.rb new file mode 100644 index 000000000..a59db50a6 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/application.rb @@ -0,0 +1,59 @@ +require 'fog/core/model' + +module Fog + module AWS + class ElasticBeanstalk + class Application < Fog::Model + identity :name, :aliases => 'ApplicationName' + attribute :template_names, :aliases => 'ConfigurationTemplates' + attribute :created_at, :aliases => 'DateCreated' + attribute :updated_at, :aliases => 'DateUpdated' + attribute :description, :aliases => 'Description' + attribute :version_names, :aliases => 'Versions' + + def initialize(attributes={}) + super + end + + def environments + requires :name + service.environments.all({'ApplicationName' => name}) + end + + def events + requires :name + service.events.all({'ApplicationName' => name}) + end + + def templates + requires :name + service.templates.all({'ApplicationName' => name}) + end + + def versions + requires :name + service.versions.all({'ApplicationName' => name}) + end + + def destroy + requires :name + service.delete_application(name) + true + end + + def save + requires :name + + options = { + 'ApplicationName' => name + } + options['Description'] = description unless description.nil? + + data = service.create_application(options).body['CreateApplicationResult']['Application'] + merge_attributes(data) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/applications.rb b/lib/fog/aws/models/beanstalk/applications.rb new file mode 100644 index 000000000..f37fe6a71 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/applications.rb @@ -0,0 +1,23 @@ +require 'fog/core/collection' +require 'fog/aws/models/beanstalk/application' + +module Fog + module AWS + class ElasticBeanstalk + class Applications < Fog::Collection + model Fog::AWS::ElasticBeanstalk::Application + + def all(application_names=[]) + data = service.describe_applications(application_names).body['DescribeApplicationsResult']['Applications'] + load(data) # data is an array of attribute hashes + end + + def get(application_name) + if data = service.describe_applications([application_name]).body['DescribeApplicationsResult']['Applications'].first + new(data) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/environment.rb b/lib/fog/aws/models/beanstalk/environment.rb new file mode 100644 index 000000000..786579916 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/environment.rb @@ -0,0 +1,145 @@ +require 'fog/core/model' + +module Fog + module AWS + class ElasticBeanstalk + class Environment < Fog::Model + identity :name, :aliases => 'EnvironmentName' + attribute :id, :aliases => 'EnvironmentId' + + attribute :application_name, :aliases => 'ApplicationName' + attribute :cname, :aliases => 'CNAME' + attribute :cname_prefix, :aliases => 'CNAMEPrefix' + attribute :created_at, :aliases => 'DateCreated' + attribute :updated_at, :aliases => 'DateUpdated' + attribute :updated_at, :aliases => 'DateUpdated' + attribute :description, :aliases => 'Description' + attribute :endpoint_url, :aliases => 'EndpointURL' + attribute :health, :aliases => 'Health' + attribute :resources, :aliases => 'Resources' + attribute :solution_stack_name, :aliases => 'SolutionStackName' + attribute :status, :aliases => 'Status' + attribute :template_name, :aliases => 'TemplateName' + attribute :version_label, :aliases => 'VersionLabel' + attribute :option_settings, :aliases => 'OptionSettings' + attribute :options_to_remove, :aliases => 'OptionsToRemove' + + def healthy? + health == 'Green' + end + + def ready? + status == 'Ready' + end + + def terminated? + status == 'Terminated' + end + + # Returns the current live resources for this environment + def live_resources + requires :id + data = service.describe_environment_resources({'EnvironmentId' => id}).body['DescribeEnvironmentResourcesResult']['EnvironmentResources'] + data.delete('EnvironmentName') # Delete the environment name from the result, only return actual resources + data + end + + # Returns the load balancer object associated with the environment. + def load_balancer(elb_connection = Fog::AWS[:elb]) + if resources.nil? + elb_connection.load_balancers.get(live_resources['LoadBalancers'].first['Name']) + else + elb_connection.load_balancers.get(resources['LoadBalancer']['LoadBalancerName']) + end + end + + # Return events related to this version + def events + requires :id + service.events.all({'EnvironmentId' => id}) + end + + # Restarts the app servers in this environment + def restart_app_server + requires :id + service.restart_app_server({'EnvironmentId' => id}) + reload + end + + # Rebuilds the environment + def rebuild + requires :id + service.rebuild_environment({'EnvironmentId' => id}) + reload + end + + def swap_cnames(source) + requires :name + service.swap_environment_cnames({ + 'SourceEnvironmentName' => source.name, + 'DestinationEnvironmentName' => name + }) + source.reload + reload + end + + # Return the version object for this environment + def version + requires :application_name, :version_label + service.versions.get(application_name, version_label) + end + + # Update the running version of this environment + def version=(new_version) + requires :id + if new_version.is_a?(String) + new_version_label = new_version + elsif new_version.is_a?(Fog::AWS::ElasticBeanstalk::Version) + new_version_label = new_version.label + else + raise "Unknown type for new_version, must be either String or Fog::AWS::ElasticBeanstalk::Version" + end + + if new_version.nil? + raise "Version label not specified." + end + + data = service.update_environment({ + 'EnvironmentId' => id, + 'VersionLabel' => new_version_label + }).body['UpdateEnvironmentResult'] + + merge_attributes(data) + end + + def destroy + requires :id + service.terminate_environment({'EnvironmentId' => id}) + true + end + + def save + requires :name, :application_name + requires_one :template_name, :solution_stack_name + + options = { + 'ApplicationName' => application_name, + 'CNAMEPrefix' => cname_prefix, + 'Description' => description, + 'EnvironmentName' => name, + 'OptionSettings' => option_settings, + 'OptionsToRemove' => options_to_remove, + 'SolutionStackName' => solution_stack_name, + 'TemplateName' => template_name, + 'VersionLabel' => version_label + } + options.delete_if {|key, value| value.nil?} + + data = service.create_environment(options).body['CreateEnvironmentResult'] + merge_attributes(data) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/environments.rb b/lib/fog/aws/models/beanstalk/environments.rb new file mode 100644 index 000000000..9f3a3dcd2 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/environments.rb @@ -0,0 +1,27 @@ +require 'fog/core/collection' +require 'fog/aws/models/beanstalk/environment' + +module Fog + module AWS + class ElasticBeanstalk + class Environments < Fog::Collection + model Fog::AWS::ElasticBeanstalk::Environment + + def all(options={}) + data = service.describe_environments(options).body['DescribeEnvironmentsResult']['Environments'] + load(data) # data is an array of attribute hashes + end + + # Gets an environment given a name. + # + def get(environment_name) + options = { 'EnvironmentNames' => [environment_name] } + + if data = service.describe_environments(options).body['DescribeEnvironmentsResult']['Environments'].first + new(data) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/event.rb b/lib/fog/aws/models/beanstalk/event.rb new file mode 100644 index 000000000..9952d297b --- /dev/null +++ b/lib/fog/aws/models/beanstalk/event.rb @@ -0,0 +1,18 @@ +require 'fog/core/model' + +module Fog + module AWS + class ElasticBeanstalk + class Event < Fog::Model + attribute :application_name, :aliases => 'ApplicationName' + attribute :environment_name, :aliases => 'EnvironmentName' + attribute :date, :aliases => 'EventDate' + attribute :message, :aliases => 'Message' + attribute :request_id, :aliases => 'RequestId' + attribute :severity, :aliases => 'Severity' + attribute :template_name, :aliases => 'TemplateName' + attribute :version_label, :aliases => 'VersionLabel' + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/events.rb b/lib/fog/aws/models/beanstalk/events.rb new file mode 100644 index 000000000..0eb77eeef --- /dev/null +++ b/lib/fog/aws/models/beanstalk/events.rb @@ -0,0 +1,17 @@ +require 'fog/core/collection' +require 'fog/aws/models/beanstalk/event' + +module Fog + module AWS + class ElasticBeanstalk + class Events < Fog::Collection + model Fog::AWS::ElasticBeanstalk::Event + + def all(options={}) + data = service.describe_events(options).body['DescribeEventsResult']['Events'] + load(data) # data is an array of attribute hashes + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/template.rb b/lib/fog/aws/models/beanstalk/template.rb new file mode 100644 index 000000000..eee306b76 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/template.rb @@ -0,0 +1,76 @@ +require 'fog/core/model' + +module Fog + module AWS + class ElasticBeanstalk + class Template < Fog::Model + attribute :name, :aliases => 'TemplateName' + attribute :application_name, :aliases => 'ApplicationName' + attribute :created_at, :aliases => 'DateCreated' + attribute :updated_at, :aliases => 'DateUpdated' + attribute :deployment_status, :aliases => 'DeploymentStatus' + attribute :description, :aliases => 'Description' + attribute :environment_id + attribute :environment_name, :aliases => 'EnvironmentName' + attribute :solution_stack_name, :aliases => 'SolutionStackName' + attribute :source_configuration + attribute :option_settings, :aliases => 'OptionSettings' + + def initialize(attributes={}) + super + end + + # Returns an array of options that may be set on this template + def options + requires :name, :application_name + data = service.describe_configuration_options({ + 'ApplicationName' => application_name, + 'TemplateName' => name + }) + data.body['DescribeConfigurationOptionsResult']['Options'] + end + + def destroy + requires :name, :application_name + service.delete_configuration_template(application_name, name) + true + end + + def save + requires :name, :application_name + + options = { + 'ApplicationName' => application_name, + 'Description' => description, + 'EnvironmentId' => environment_id, + 'OptionSettings' => option_settings, + 'SolutionStackName' => solution_stack_name, + 'SourceConfiguration' => source_configuration, + 'TemplateName' => name + } + options.delete_if {|key, value| value.nil?} + + data = service.create_configuration_template(options).body['CreateConfigurationTemplateResult'] + merge_attributes(data) + true + end + + def modify(new_attributes) + requires :name, :application_name + + options = { + 'ApplicationName' => application_name, + 'Description' => new_attributes[:description], + 'OptionSettings' => new_attributes[:option_settings], + 'TemplateName' => name + } + options.delete_if {|key, value| value.nil?} + + data = service.update_configuration_template(options).body['UpdateConfigurationTemplateResult'] + merge_attributes(data) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/templates.rb b/lib/fog/aws/models/beanstalk/templates.rb new file mode 100644 index 000000000..2bc7eb4df --- /dev/null +++ b/lib/fog/aws/models/beanstalk/templates.rb @@ -0,0 +1,68 @@ +require 'fog/core/collection' +require 'fog/aws/models/beanstalk/template' + +module Fog + module AWS + class ElasticBeanstalk + class Templates < Fog::Collection + model Fog::AWS::ElasticBeanstalk::Template + + # Describes all configuration templates, may optionally pass an ApplicationName filter + # + # Note: This is currently an expensive operation requiring multiple API calls due to a lack of + # a describe configuration templates call in the Aws API. + def all(options={}) + application_filter = [] + if options.key?('ApplicationName') + application_filter << options['ApplicationName'] + end + + # Initialize with empty array + data = [] + + applications = service.describe_applications(application_filter).body['DescribeApplicationsResult']['Applications'] + applications.each { |application| + application['ConfigurationTemplates'].each { |template_name| + begin + options = { + 'ApplicationName' => application['ApplicationName'], + 'TemplateName' => template_name + } + settings = service.describe_configuration_settings(options).body['DescribeConfigurationSettingsResult']['ConfigurationSettings'] + if settings.length == 1 + # Add to data + data << settings.first + end + rescue Fog::AWS::ElasticBeanstalk::InvalidParameterError + # Ignore + end + + } + } + + load(data) # data is an array of attribute hashes + end + + def get(application_name, template_name) + options = { + 'ApplicationName' => application_name, + 'TemplateName' => template_name + } + + result = nil + # There is no describe call for templates, so we must use describe_configuration_settings. Unfortunately, + # it throws an exception if template name doesn't exist, which is inconsistent, catch and return nil + begin + data = service.describe_configuration_settings(options).body['DescribeConfigurationSettingsResult']['ConfigurationSettings'] + if data.length == 1 + result = new(data.first) + end + rescue Fog::AWS::ElasticBeanstalk::InvalidParameterError + + end + result + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/version.rb b/lib/fog/aws/models/beanstalk/version.rb new file mode 100644 index 000000000..98c5708a8 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/version.rb @@ -0,0 +1,77 @@ +require 'fog/core/model' + +module Fog + module AWS + class ElasticBeanstalk + class Version < Fog::Model + attribute :label, :aliases => 'VersionLabel' + attribute :application_name, :aliases => 'ApplicationName' + attribute :created_at, :aliases => 'DateCreated' + attribute :updated_at, :aliases => 'DateUpdated' + attribute :description, :aliases => 'Description' + attribute :source_bundle, :aliases => 'SourceBundle' + attribute :auto_create_application # FIXME - should be write only + + def initialize(attributes={}) + super + end + + # Return events related to this version + def events + requires :label, :application_name + service.events.all({ + 'ApplicationName' => application_name, + 'VersionLabel' => label + }) + end + + # Returns environments running this version + def environments + requires :label, :application_name + service.environments.all({ + 'ApplicationName' => application_name, + 'VersionLabel' => label + }) + end + + def destroy(delete_source_bundle = nil) + requires :label, :application_name + service.delete_application_version(application_name, label, delete_source_bundle) + true + end + + def save + requires :label, :application_name + + options = { + 'ApplicationName' => application_name, + 'AutoCreateApplication' => auto_create_application, + 'Description' => description, + 'SourceBundle' => source_bundle, + 'VersionLabel' => label + } + options.delete_if {|key, value| value.nil?} + + data = service.create_application_version(options).body['CreateApplicationVersionResult']['ApplicationVersion'] + merge_attributes(data) + true + end + + # Updates the version label with the current property values. Currently only updates description + def update + requires :label, :application_name + + options = { + 'ApplicationName' => application_name, + 'Description' => description, + 'VersionLabel' => label + } + options.delete_if {|key, value| value.nil?} + + data = service.update_application_version(options).body['UpdateApplicationVersionResult']['ApplicationVersion'] + merge_attributes(data) + end + end + end + end +end diff --git a/lib/fog/aws/models/beanstalk/versions.rb b/lib/fog/aws/models/beanstalk/versions.rb new file mode 100644 index 000000000..be56a0537 --- /dev/null +++ b/lib/fog/aws/models/beanstalk/versions.rb @@ -0,0 +1,29 @@ +require 'fog/core/collection' +require 'fog/aws/models/beanstalk/version' + +module Fog + module AWS + class ElasticBeanstalk + class Versions < Fog::Collection + model Fog::AWS::ElasticBeanstalk::Version + + def all(options={}) + data = service.describe_application_versions(options).body['DescribeApplicationVersionsResult']['ApplicationVersions'] + load(data) # data is an array of attribute hashes + end + + def get(application_name, version_label) + if data = service.describe_application_versions({ + 'ApplicationName' => application_name, + 'VersionLabels' => [version_label] + }).body['DescribeApplicationVersionsResult']['ApplicationVersions'] + if data.length == 1 + new(data.first) + end + + end + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/distribution.rb b/lib/fog/aws/models/cdn/distribution.rb new file mode 100644 index 000000000..74816132c --- /dev/null +++ b/lib/fog/aws/models/cdn/distribution.rb @@ -0,0 +1,90 @@ +require 'fog/core/model' +require 'fog/aws/models/cdn/invalidations' +require 'fog/aws/models/cdn/distribution_helper' + +module Fog + module CDN + class Aws + class Distribution < Fog::Model + include Fog::CDN::AWS::DistributionHelper + + identity :id, :aliases => 'Id' + + attribute :caller_reference, :aliases => 'CallerReference' + attribute :last_modified_time, :aliases => 'LastModifiedTime' + attribute :status, :aliases => 'Status' + attribute :s3_origin, :aliases => 'S3Origin' + attribute :custom_origin, :aliases => 'CustomOrigin' + attribute :cname, :aliases => 'CNAME' + attribute :comment, :aliases => 'Comment' + attribute :enabled, :aliases => 'Enabled' + attribute :in_progress_invalidation_batches, :aliases => 'InProgressInvalidationBatches' + attribute :logging, :aliases => 'Logging' + attribute :trusted_signers, :aliases => 'TrustedSigners' + attribute :default_root_object,:aliases => 'DefaultRootObject' + attribute :domain, :aliases => 'DomainName' + attribute :etag, :aliases => ['Etag', 'ETag'] + + # items part of DistributionConfig + CONFIG = [ :caller_reference, :origin, :cname, :comment, :enabled, :logging, :trusted_signers, :default_root_object ] + + def initialize(new_attributes = {}) + super(distribution_config_to_attributes(new_attributes)) + end + + def invalidations + @invalidations ||= begin + Fog::CDN::AWS::Invalidations.new( + :distribution => self, + :service => service + ) + end + end + + def save + requires_one :s3_origin, :custom_origin + options = attributes_to_options + response = identity ? put_distribution_config(identity, etag, options) : post_distribution(options) + etag = response.headers['ETag'] + merge_attributes(response.body) + true + end + + private + + def delete_distribution(identity, etag) + service.delete_distribution(identity, etag) + end + + def put_distribution_config(identity, etag, options) + service.put_distribution_config(identity, etag, options) + end + + def post_distribution(options = {}) + service.post_distribution(options) + end + + def attributes_to_options + options = { + 'CallerReference' => caller_reference, + 'S3Origin' => s3_origin, + 'CustomOrigin' => custom_origin, + 'CNAME' => cname, + 'Comment' => comment, + 'Enabled' => enabled, + 'Logging' => logging, + 'TrustedSigners' => trusted_signers, + 'DefaultRootObject' => default_root_object + } + options.reject! { |k,v| v.nil? } + options.reject! { |k,v| v.respond_to?(:empty?) && v.empty? } + options + end + + def distribution_config_to_attributes(new_attributes = {}) + new_attributes.merge(new_attributes.delete('DistributionConfig') || {}) + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/distribution_helper.rb b/lib/fog/aws/models/cdn/distribution_helper.rb new file mode 100644 index 000000000..7568368a1 --- /dev/null +++ b/lib/fog/aws/models/cdn/distribution_helper.rb @@ -0,0 +1,60 @@ +require 'fog/core/collection' + +module Fog + module CDN + class Aws + module DistributionHelper + def destroy + requires :identity, :etag, :caller_reference + raise "Distribution must be disabled to be deleted" unless disabled? + delete_distribution(identity, etag) + true + end + + def enabled? + requires :identity + !!enabled and ready? + end + + def disabled? + requires :identity + not enabled? and ready? + end + + def custom_origin? + requires :identity + not custom_origin.nil? + end + + def ready? + requires :identity + status == 'Deployed' + end + + def enable + requires :identity + reload if etag.nil? or caller_reference.nil? + unless enabled? + self.enabled = true + response = put_distribution_config(identity, etag, attributes_to_options) + etag = response.headers['ETag'] + merge_attributes(response.body) + end + true + end + + def disable + requires :identity + reload if etag.nil? or caller_reference.nil? + if enabled? + self.enabled = false + response = put_distribution_config(identity, etag, attributes_to_options) + etag = response.headers['ETag'] + merge_attributes(response.body) + end + true + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/distributions.rb b/lib/fog/aws/models/cdn/distributions.rb new file mode 100644 index 000000000..941ba8862 --- /dev/null +++ b/lib/fog/aws/models/cdn/distributions.rb @@ -0,0 +1,30 @@ +require 'fog/core/collection' +require 'fog/aws/models/cdn/distribution' +require 'fog/aws/models/cdn/distributions_helper' + +module Fog + module CDN + class Aws + class Distributions < Fog::Collection + include Fog::CDN::AWS::DistributionsHelper + + model Fog::CDN::AWS::Distribution + + attribute :marker, :aliases => 'Marker' + attribute :max_items, :aliases => 'MaxItems' + attribute :is_truncated, :aliases => 'IsTruncated' + + def get_distribution(dist_id) + service.get_distribution(dist_id) + end + + def list_distributions(options = {}) + service.get_distribution_list(options) + end + + alias_method :each_distribution_this_page, :each + alias_method :each, :each_distribution + end + end + end +end diff --git a/lib/fog/aws/models/cdn/distributions_helper.rb b/lib/fog/aws/models/cdn/distributions_helper.rb new file mode 100644 index 000000000..aa9e1844c --- /dev/null +++ b/lib/fog/aws/models/cdn/distributions_helper.rb @@ -0,0 +1,45 @@ +require 'fog/core/collection' + +module Fog + module CDN + class Aws + module DistributionsHelper + + def all(options = {}) + merge_attributes(options) + data = list_distributions(options).body + merge_attributes('IsTruncated' => data['IsTruncated'], 'Marker' => data['Marker'], 'MaxItems' => data['MaxItems']) + if summary = data['DistributionSummary'] + load(summary.map { |a| { 'DistributionConfig' => a } }) + else + load((data['StreamingDistributionSummary'] || {}).map { |a| { 'StreamingDistributionConfig' => a }}) + end + end + + def get(dist_id) + response = get_distribution(dist_id) + data = response.body.merge({'ETag' => response.headers['ETag']}) + new(data) + rescue Excon::Errors::NotFound + nil + end + + def each_distribution + if !block_given? + self + else + subset = dup.all + + subset.each_distribution_this_page {|f| yield f} + while subset.is_truncated + subset = subset.all('Marker' => subset.marker, 'MaxItems' => 1000) + subset.each_distribution_this_page {|f| yield f} + end + + self + end + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/invalidation.rb b/lib/fog/aws/models/cdn/invalidation.rb new file mode 100644 index 000000000..1239f043a --- /dev/null +++ b/lib/fog/aws/models/cdn/invalidation.rb @@ -0,0 +1,60 @@ +require 'fog/core/model' + +module Fog + module CDN + class Aws + class Invalidation < Fog::Model + identity :id, :aliases => 'Id' + + attribute :status, :aliases => 'Status' + attribute :create_time, :aliases => 'CreateTime' + attribute :caller_reference, :aliases => 'CallerReference' + attribute :paths, :aliases => 'Paths' + + def initialize(new_attributes={}) + new_attributes[:caller_reference] ||= Time.now.utc.to_i.to_s + super(invalidation_to_attributes(new_attributes)) + end + + def distribution + @distribution + end + + def ready? + requires :id, :status + status == 'Completed' + end + + def save + requires :paths, :caller_reference + raise "Submitted invalidation cannot be submitted again" if persisted? + response = service.post_invalidation(distribution.identity, paths, caller_reference) + merge_attributes(invalidation_to_attributes(response.body)) + true + end + + def destroy + # invalidations can't be removed, but tests are requiring they do :) + true + end + + private + + def distribution=(dist) + @distribution = dist + end + + def invalidation_to_attributes(new_attributes={}) + invalidation_batch = new_attributes.delete('InvalidationBatch') || {} + if invalidation_batch['Path'] + new_attributes[:paths] = invalidation_batch['Path'] + end + if invalidation_batch['CallerReference'] + new_attributes[:caller_reference] = invalidation_batch['CallerReference'] + end + new_attributes + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/invalidations.rb b/lib/fog/aws/models/cdn/invalidations.rb new file mode 100644 index 000000000..91b93efdc --- /dev/null +++ b/lib/fog/aws/models/cdn/invalidations.rb @@ -0,0 +1,50 @@ +require 'fog/core/collection' +require 'fog/aws/models/cdn/invalidation' + +module Fog + module CDN + class Aws + class Invalidations < Fog::Collection + attribute :is_truncated, :aliases => ['IsTruncated'] + attribute :max_items, :aliases => ['MaxItems'] + attribute :next_marker, :aliases => ['NextMarker'] + attribute :marker, :aliases => ['Marker'] + + attribute :distribution + + model Fog::CDN::AWS::Invalidation + + def all(options = {}) + requires :distribution + options[:max_items] ||= max_items + options.delete_if {|key, value| value.nil?} + + data = service.get_invalidation_list(distribution.identity, options).body + + merge_attributes(data.reject {|key, value| !['IsTruncated', 'MaxItems', 'NextMarker', 'Marker'].include?(key)}) + + load(data['InvalidationSummary']) + end + + def get(invalidation_id) + requires :distribution + + data = service.get_invalidation(distribution.identity, invalidation_id).body + + if data + invalidation = new(data) + else + nil + end + rescue Excon::Errors::NotFound + nil + end + + def new(attributes = {}) + requires :distribution + super({ :distribution => distribution }.merge!(attributes)) + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/streaming_distribution.rb b/lib/fog/aws/models/cdn/streaming_distribution.rb new file mode 100644 index 000000000..9ed911b15 --- /dev/null +++ b/lib/fog/aws/models/cdn/streaming_distribution.rb @@ -0,0 +1,74 @@ +require 'fog/core/model' +require 'fog/aws/models/cdn/invalidations' +require 'fog/aws/models/cdn/distribution_helper' + +module Fog + module CDN + class Aws + class StreamingDistribution < Fog::Model + include Fog::CDN::AWS::DistributionHelper + + identity :id, :aliases => 'Id' + + attribute :caller_reference, :aliases => 'CallerReference' + attribute :last_modified_time, :aliases => 'LastModifiedTime' + attribute :status, :aliases => 'Status' + attribute :s3_origin, :aliases => 'S3Origin' + attribute :cname, :aliases => 'CNAME' + attribute :comment, :aliases => 'Comment' + attribute :enabled, :aliases => 'Enabled' + attribute :logging, :aliases => 'Logging' + attribute :domain, :aliases => 'DomainName' + attribute :etag, :aliases => ['Etag', 'ETag'] + + # items part of DistributionConfig + CONFIG = [ :caller_reference, :cname, :comment, :enabled, :logging ] + + def initialize(new_attributes = {}) + super(distribution_config_to_attributes(new_attributes)) + end + + def save + requires_one :s3_origin + options = attributes_to_options + response = identity ? put_distribution_config(identity, etag, options) : post_distribution(options) + etag = response.headers['ETag'] + merge_attributes(response.body) + true + end + + private + + def delete_distribution(identity, etag) + service.delete_streaming_distribution(identity, etag) + end + + def put_distribution_config(identity, etag, options) + service.put_streaming_distribution_config(identity, etag, options) + end + + def post_distribution(options = {}) + service.post_streaming_distribution(options) + end + + def attributes_to_options + options = { + 'CallerReference' => caller_reference, + 'S3Origin' => s3_origin, + 'CNAME' => cname, + 'Comment' => comment, + 'Enabled' => enabled, + 'Logging' => logging, + } + options.reject! { |k,v| v.nil? } + options.reject! { |k,v| v.respond_to?(:empty?) && v.empty? } + options + end + + def distribution_config_to_attributes(new_attributes = {}) + new_attributes.merge(new_attributes.delete('StreamingDistributionConfig') || {}) + end + end + end + end +end diff --git a/lib/fog/aws/models/cdn/streaming_distributions.rb b/lib/fog/aws/models/cdn/streaming_distributions.rb new file mode 100644 index 000000000..29092626f --- /dev/null +++ b/lib/fog/aws/models/cdn/streaming_distributions.rb @@ -0,0 +1,30 @@ +require 'fog/core/collection' +require 'fog/aws/models/cdn/streaming_distribution' +require 'fog/aws/models/cdn/distributions_helper' + +module Fog + module CDN + class Aws + class StreamingDistributions < Fog::Collection + include Fog::CDN::AWS::DistributionsHelper + + model Fog::CDN::AWS::StreamingDistribution + + attribute :marker, :aliases => 'Marker' + attribute :max_items, :aliases => 'MaxItems' + attribute :is_truncated, :aliases => 'IsTruncated' + + def get_distribution(dist_id) + service.get_streaming_distribution(dist_id) + end + + def list_distributions(options = {}) + service.get_streaming_distribution_list(options) + end + + alias_method :each_distribution_this_page, :each + alias_method :each, :each_distribution + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/alarm.rb b/lib/fog/aws/models/cloud_watch/alarm.rb new file mode 100644 index 000000000..406cd2e19 --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/alarm.rb @@ -0,0 +1,60 @@ +require 'fog/core/model' + +module Fog + module AWS + class CloudWatch + class Alarm < Fog::Model + identity :id, :aliases => 'AlarmName' + + attribute :actions_enabled, :aliases => 'ActionsEnabled' + attribute :alarm_actions, :aliases => 'AlarmActions' + attribute :arn, :aliases => 'AlarmArn' + attribute :alarm_configuration_updated_timestamp, :aliases => 'AlarmConfigurationUpdatedTimestamp' + attribute :alarm_description, :aliases => 'AlarmDescription' + attribute :comparison_operator, :aliases => 'ComparisonOperator' + attribute :dimensions, :aliases => 'Dimensions' + attribute :evaluation_periods, :aliases => 'EvaluationPeriods' + attribute :insufficient_data_actions, :aliases => 'InsufficientDataActions' + attribute :metric_name, :aliases => 'MetricName' + attribute :namespace, :aliases => 'Namespace' + attribute :ok_actions, :aliases => 'OKActions' + attribute :period, :aliases => 'Period' + attribute :state_reason, :aliases => 'StateReason' + attribute :state_reason_data, :aliases => 'StateReasonData' + attribute :state_updated_timestamp, :aliases => 'StateUpdatedTimestamp' + attribute :state_value, :aliases => 'StateValue' + attribute :statistic, :aliases => 'Statistic' + attribute :threshold, :aliases => 'Threshold' + attribute :unit, :aliases => 'Unit' + + def initialize(attributes) + attributes['EvaluationPeriods'] ||= 1 + attributes['Namespace'] ||= 'Aws/EC2' + super + end + + def save + requires :id + requires :comparison_operator + requires :evaluation_periods + requires :metric_name + requires :namespace + requires :period + requires :statistic + requires :threshold + + options = Hash[self.class.aliases.map { |key, value| [key, send(value)] }] + options.delete_if { |key, value| value.nil? } + + service.put_metric_alarm(options) + reload + end + + def destroy + requires :id + service.delete_alarms(id) + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/alarm_data.rb b/lib/fog/aws/models/cloud_watch/alarm_data.rb new file mode 100644 index 000000000..772e6b36b --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/alarm_data.rb @@ -0,0 +1,38 @@ +require 'fog/core/collection' +require 'fog/aws/models/cloud_watch/alarm_datum' + +module Fog + module AWS + class CloudWatch + class AlarmData < Fog::Collection + model Fog::AWS::CloudWatch::AlarmDatum + + def all(conditions={}) + data = service.describe_alarms(conditions).body['DescribeAlarmsResult']['MetricAlarms'] + load(data) # data is an array of attribute hashes + end + + def get(namespace, metric_name, dimensions=nil, period=nil, statistic=nil, unit=nil) + list_opts = {'Namespace' => namespace, 'MetricName' => metric_name} + if dimensions + dimensions_array = dimensions.map do |name, value| + {'Name' => name, 'Value' => value} + end + list_opts.merge!('Dimensions' => dimensions_array) + end + if period + list_opts.merge!('Period' => period) + end + if statistic + list_opts.merge!('Statistic' => statistic) + end + if unit + list_opts.merge!('Unit' => unit) + end + data = service.describe_alarms_for_metric(list_opts).body['DescribeAlarmsForMetricResult']['MetricAlarms'] + load(data) + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/alarm_datum.rb b/lib/fog/aws/models/cloud_watch/alarm_datum.rb new file mode 100644 index 000000000..ae20e81dc --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/alarm_datum.rb @@ -0,0 +1,65 @@ +require 'fog/core/model' + +module Fog + module AWS + class CloudWatch + class AlarmDatum < Fog::Model + attribute :alarm_name, :aliases => 'AlarmName' + attribute :metric_name, :aliases => 'MetricName' + attribute :namespace, :aliases => 'Namespace' + attribute :dimensions, :aliases => 'Dimensions' + attribute :alarm_description, :aliases => 'AlarmDescription' + attribute :alarm_arn, :aliases => 'AlarmArn' + attribute :state_value, :aliases => 'StateValue' + attribute :statistic, :aliases => 'Statistic' + attribute :comparison_operator, :aliases => 'ComparisonOperator' + attribute :state_reason, :aliases => 'StateReason' + attribute :action_enabled, :aliases => 'ActionsEnabled' + attribute :period, :aliases => 'Period' + attribute :evaluation_periods, :aliases => 'EvaluationPeriods' + attribute :threshold, :aliases => 'Threshold' + attribute :alarm_actions, :aliases => 'AlarmActions' + attribute :ok_actions, :aliases => 'OKActions' + attribute :insufficient_actions, :aliases => 'InsufficientDataActions' + attribute :unit, :aliases => 'Unit' + attribute :state_updated_timestamp, :aliases => 'StateUpdatedTimestamp' + attribute :alarm_configuration_updated_timestamp, :aliases => 'AlarmConfigurationUpdatedTimestamp' + + def save + requires :alarm_name + requires :comparison_operator + requires :evaluation_periods + requires :metric_name + requires :namespace + requires :period + requires :statistic + requires :threshold + + alarm_definition = { + 'AlarmName' => alarm_name, + 'ComparisonOperator' => comparison_operator, + 'EvaluationPeriods' => evaluation_periods, + 'MetricName' => metric_name, + 'Namespace' => namespace, + 'Period' => period, + 'Statistic' => statistic, + 'Threshold' => threshold + } + + alarm_definition.merge!('ActionsEnabled' => action_enabled) if action_enabled + alarm_definition.merge!('AlarmActions' => alarm_actions) if alarm_actions + alarm_definition.merge!('AlarmDescription' => alarm_description) if alarm_description + + #dimension is an array of Name/Value pairs, ex. [{'Name'=>'host', 'Value'=>'localhost'},{'Name'=>'version', 'Value'=>'0.11.0'}] + alarm_definition.merge!('Dimensions' => dimensions) if dimensions + alarm_definition.merge!('InsufficientDataActions' => insufficient_actions) if insufficient_actions + alarm_definition.merge!('OKActions' => ok_actions) if ok_actions + alarm_definition.merge!('Unit' => unit) if unit + + service.put_metric_alarm(alarm_definition) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/alarm_histories.rb b/lib/fog/aws/models/cloud_watch/alarm_histories.rb new file mode 100644 index 000000000..7a00d016a --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/alarm_histories.rb @@ -0,0 +1,17 @@ +require 'fog/core/collection' +require 'fog/aws/models/cloud_watch/alarm_history' + +module Fog + module AWS + class CloudWatch + class AlarmHistories < Fog::Collection + model Fog::AWS::CloudWatch::AlarmHistory + + def all(conditions={}) + data = service.describe_alarm_history(conditions).body['DescribeAlarmHistoryResult']['AlarmHistoryItems'] + load(data) # data is an array of attribute hashes + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/alarm_history.rb b/lib/fog/aws/models/cloud_watch/alarm_history.rb new file mode 100644 index 000000000..4c16db39c --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/alarm_history.rb @@ -0,0 +1,15 @@ +require 'fog/core/model' + +module Fog + module AWS + class CloudWatch + class AlarmHistory < Fog::Model + attribute :alarm_name, :aliases => 'AlarmName' + attribute :end_date, :aliases => 'EndDate' + attribute :history_item_type, :aliases => 'HistoryItemType' + attribute :max_records, :aliases => 'MaxRecords' + attribute :start_date, :aliases => 'StartDate' + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/alarms.rb b/lib/fog/aws/models/cloud_watch/alarms.rb new file mode 100644 index 000000000..47bb1629f --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/alarms.rb @@ -0,0 +1,45 @@ +require 'fog/core/collection' +require 'fog/aws/models/cloud_watch/alarm' + +module Fog + module AWS + class CloudWatch + class Alarms < Fog::Collection + model Fog::AWS::CloudWatch::Alarm + + def all + data = [] + next_token = nil + loop do + body = service.describe_alarms('NextToken' => next_token).body + data += body['DescribeAlarmsResult']['MetricAlarms'] + next_token = body['ResponseMetadata']['NextToken'] + break if next_token.nil? + end + load(data) + end + + def get(identity) + data = service.describe_alarms('AlarmNames' => identity).body['DescribeAlarmsResult']['MetricAlarms'].first + new(data) unless data.nil? + end + + #alarm_names is an array of alarm names + def delete(alarm_names) + service.delete_alarms(alarm_names) + true + end + + def disable(alarm_names) + service.disable_alarm_actions(alarm_names) + true + end + + def enable(alarm_names) + service.enable_alarm_actions(alarm_names) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/metric.rb b/lib/fog/aws/models/cloud_watch/metric.rb new file mode 100644 index 000000000..f923e674d --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/metric.rb @@ -0,0 +1,13 @@ +require 'fog/core/model' + +module Fog + module AWS + class CloudWatch + class Metric < Fog::Model + attribute :name, :aliases => 'MetricName' + attribute :namespace, :aliases => 'Namespace' + attribute :dimensions, :aliases => 'Dimensions' + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/metric_statistic.rb b/lib/fog/aws/models/cloud_watch/metric_statistic.rb new file mode 100644 index 000000000..eddd6d7ca --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/metric_statistic.rb @@ -0,0 +1,44 @@ +require 'fog/core/model' + +module Fog + module AWS + class CloudWatch + class MetricStatistic < Fog::Model + attribute :label, :aliases => 'Label' + attribute :minimum, :aliases => 'Minimum' + attribute :maximum, :aliases => 'Maximum' + attribute :sum, :aliases => 'Sum' + attribute :average, :aliases => 'Average' + attribute :sample_count, :aliases => 'SampleCount' + attribute :timestamp, :aliases => 'Timestamp' + attribute :unit, :aliases => 'Unit' + attribute :metric_name, :aliases => 'MetricName' + attribute :namespace, :aliases => 'Namespace' + attribute :dimensions, :aliases => 'Dimensions' + attribute :value + + def save + requires :metric_name + requires :namespace + requires :unit + + put_opts = {'MetricName' => metric_name, 'Unit' => unit} + put_opts.merge!('Dimensions' => dimensions) if dimensions + if value + put_opts.merge!('Value' => value) + else + put_opts.merge!('StatisticValues' => { + 'Minimum' => minimum, + 'Maximum' => maximum, + 'Sum' => sum, + 'Average' => average, + 'SampleCount' => sample_count + }) + end + service.put_metric_data(namespace, [put_opts]) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/metric_statistics.rb b/lib/fog/aws/models/cloud_watch/metric_statistics.rb new file mode 100644 index 000000000..76fe47776 --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/metric_statistics.rb @@ -0,0 +1,22 @@ +require 'fog/core/collection' +require 'fog/aws/models/cloud_watch/metric_statistic' + +module Fog + module AWS + class CloudWatch + class MetricStatistics < Fog::Collection + model Fog::AWS::CloudWatch::MetricStatistic + + def all(conditions) + metricName = conditions['MetricName'] + namespace = conditions['Namespace'] + dimensions = conditions['Dimensions'] + get_metric_opts = {"StartTime" => (Time.now-3600).iso8601, "EndTime" => Time.now.iso8601, "Period" => 300}.merge(conditions) + data = service.get_metric_statistics(get_metric_opts).body['GetMetricStatisticsResult']['Datapoints'] + data.map! { |datum| datum.merge('MetricName' => metricName, 'Namespace' => namespace, 'Dimensions' => dimensions) } + load(data) # data is an array of attribute hashes + end + end + end + end +end diff --git a/lib/fog/aws/models/cloud_watch/metrics.rb b/lib/fog/aws/models/cloud_watch/metrics.rb new file mode 100644 index 000000000..0c0e6275a --- /dev/null +++ b/lib/fog/aws/models/cloud_watch/metrics.rb @@ -0,0 +1,50 @@ +require 'fog/core/collection' +require 'fog/aws/models/cloud_watch/metric' + +module Fog + module AWS + class CloudWatch + class Metrics < Fog::Collection + attribute :next_token, :aliases => 'NextToken' + + model Fog::AWS::CloudWatch::Metric + + def all(conditions={}) + result = service.list_metrics(conditions).body['ListMetricsResult'] + merge_attributes("NextToken" => result["NextToken"]) + load(result['Metrics']) # an array of attribute hashes + end + + alias_method :each_metric_this_page, :each + def each + if !block_given? + self + else + subset = dup.all + subset.each_metric_this_page {|m| yield m } + + while next_token = subset.next_token + subset = subset.all("NextToken" => next_token) + subset.each_metric_this_page {|m| yield m } + end + + self + end + end + + def get(namespace, metric_name, dimensions=nil) + list_opts = {'Namespace' => namespace, 'MetricName' => metric_name} + if dimensions + dimensions_array = dimensions.map do |name, value| + {'Name' => name, 'Value' => value} + end + # list_opts.merge!('Dimensions' => dimensions_array) + end + if data = service.list_metrics(list_opts).body['ListMetricsResult']['Metrics'].first + new(data) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/address.rb b/lib/fog/aws/models/compute/address.rb new file mode 100644 index 000000000..c66748d8f --- /dev/null +++ b/lib/fog/aws/models/compute/address.rb @@ -0,0 +1,74 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Address < Fog::Model + identity :public_ip, :aliases => 'publicIp' + + attribute :allocation_id, :aliases => 'allocationId' + attribute :association_id, :aliases => 'associationId' + attribute :server_id, :aliases => 'instanceId' + attribute :network_interface_id, :aliases => 'networkInterfaceId' + attribute :network_interface_owner_id, :aliases => 'networkInterfaceOwnerId' + attribute :domain + + def initialize(attributes = {}) + # assign server first to prevent race condition with persisted? + self.server = attributes.delete(:server) + super + end + + def destroy + requires :public_ip + + service.release_address(allocation_id || public_ip) + true + end + + def server=(new_server) + if new_server + associate(new_server) + else + disassociate + end + end + + def server + service.servers.get(server_id) + end + + def save + raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted? + data = service.allocate_address(domain).body + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + if @server + self.server = @server + end + true + end + + private + + def associate(new_server) + unless persisted? + @server = new_server + else + @server = nil + self.server_id = new_server.id + service.associate_address(server_id, public_ip, network_interface_id, allocation_id) + end + end + + def disassociate + @server = nil + self.server_id = nil + if persisted? + service.disassociate_address(public_ip) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/addresses.rb b/lib/fog/aws/models/compute/addresses.rb new file mode 100644 index 000000000..82d26b768 --- /dev/null +++ b/lib/fog/aws/models/compute/addresses.rb @@ -0,0 +1,96 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/address' + +module Fog + module Compute + class Aws + class Addresses < Fog::Collection + attribute :filters + attribute :server + + model Fog::Compute::AWS::Address + + # Used to create an IP address + # + # ==== Returns + # + #>> Aws.addresses.create + # + # + # The IP address can be retrieved by running Aws.addresses.get("test"). See get method below. + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Aws.addresses.all + # + # ==== Returns + # + # Returns an array of all IP addresses + # + #>> Aws.addresses.all + # , + # ....... + # + # ] + # > + #>> + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters_arg.class} param is deprecated, use all('public-ip' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'public-ip' => [*filters_arg]} + end + self.filters = filters_arg + data = service.describe_addresses(filters).body + load( + data['addressesSet'].map do |address| + address.reject {|key, value| value.nil? || value.empty? } + end + ) + if server + self.replace(self.select {|address| address.server_id == server.id}) + end + self + end + + # Used to retrieve an IP address + # + # public_ip is required to get the associated IP information. + # + # You can run the following command to get the details: + # Aws.addresses.get("76.7.46.54") + + def get(public_ip) + if public_ip + self.class.new(:service => service).all('public-ip' => public_ip).first + end + end + + def new(attributes = {}) + if server + super({ :server => server }.merge!(attributes)) + else + super(attributes) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/dhcp_option.rb b/lib/fog/aws/models/compute/dhcp_option.rb new file mode 100644 index 000000000..7f1cc9a96 --- /dev/null +++ b/lib/fog/aws/models/compute/dhcp_option.rb @@ -0,0 +1,66 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class DhcpOption < Fog::Model + identity :id, :aliases => 'dhcpOptionsId' + attribute :dhcp_configuration_set, :aliases => 'dhcpConfigurationSet' + attribute :tag_set, :aliases => 'tagSet' + + def initialize(attributes={}) + super + end + + # Associates an existing dhcp configration set with a VPC + # + # dhcp_option.attach(dopt-id, vpc-id) + # + # ==== Returns + # + # True or false depending on the result + # + def associate(vpc_id) + requires :id + service.associate_dhcp_options(id, vpc_id) + reload + end + + # Removes an existing dhcp configuration set + # + # dhcp_option.destroy + # + # ==== Returns + # + # True or false depending on the result + # + + def destroy + requires :id + service.delete_dhcp_options(id) + true + end + + # Create a dhcp configuration set + # + # >> g = Aws.dhcp_options.new() + # >> g.save + # + # == Returns: + # + # requestId and a dhcpOptions object + # + + def save + requires :dhcp_configuration_set + data = service.create_dhcp_options(dhcp_configuration_set).body['dhcpOptionsSet'].first + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + true + + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/dhcp_options.rb b/lib/fog/aws/models/compute/dhcp_options.rb new file mode 100644 index 000000000..3f3813d32 --- /dev/null +++ b/lib/fog/aws/models/compute/dhcp_options.rb @@ -0,0 +1,87 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/dhcp_option' + +module Fog + module Compute + class Aws + class DhcpOptions < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::DhcpOption + + # Creates a new dhcp option + # + # Aws.dhcp_options.new + # + # ==== Returns + # + # Returns the details of the new DHCP options + # + #>> Aws.dhcp_options.new + #=> + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all DhcpOptions that have been created + # + # Aws.dhcp_options.all + # + # ==== Returns + # + # Returns an array of all DhcpOptions + # + #>> Aws.dhcp_options.all + #"vpc-some-id", "state"=>"available"}, + #tag_set={} + #> + #] + #> + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.warning("all with #{filters_arg.class} param is deprecated, use all('internet-gateway-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'dhcp-options-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_dhcp_options(filters).body + load(data['dhcpOptionsSet']) + end + + # Used to retrieve an DhcpOption + # + # You can run the following command to get the details: + # Aws.dhcp_options.get("dopt-12345678") + # + # ==== Returns + # + #>> Aws.dhcp_options.get("dopt-12345678") + #=> "vpc-12345678", "state"=>"available"}, + #tag_set={} + #> + # + + def get(dhcp_options_id) + if dhcp_options_id + self.class.new(:service => service).all('dhcp-options-id' => dhcp_options_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/flavor.rb b/lib/fog/aws/models/compute/flavor.rb new file mode 100644 index 000000000..e9b39ef2b --- /dev/null +++ b/lib/fog/aws/models/compute/flavor.rb @@ -0,0 +1,19 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Flavor < Fog::Model + identity :id + + attribute :bits + attribute :cores + attribute :disk + attribute :name + attribute :ram + attribute :ebs_optimized_available + attribute :instance_store_volumes + end + end + end +end diff --git a/lib/fog/aws/models/compute/flavors.rb b/lib/fog/aws/models/compute/flavors.rb new file mode 100644 index 000000000..dc91e9ba7 --- /dev/null +++ b/lib/fog/aws/models/compute/flavors.rb @@ -0,0 +1,606 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/flavor' + +module Fog + module Compute + class Aws + FLAVORS = [ + { + :id => 't1.micro', + :name => 'Micro Instance', + :bits => 0, + :cores => 2, + :disk => 0, + :ram => 613, + :ebs_optimized_available => false, + :instance_store_volumes => 0 + }, + { + :id => 't2.micro', + :name => 'Micro Instance', + :bits => 64, + :cores => 1, + :disk => 0, + :ram => 1024, + :ebs_optimized_available => false, + :instance_store_volumes => 0 + }, + { + :id => 't2.small', + :name => 'Micro Instance', + :bits => 64, + :cores => 1, + :disk => 0, + :ram => 2048, + :ebs_optimized_available => false, + :instance_store_volumes => 0 + }, + { + :id => 't2.medium', + :name => 'Micro Instance', + :bits => 64, + :cores => 2, + :disk => 0, + :ram => 4096, + :ebs_optimized_available => false, + :instance_store_volumes => 0 + }, + { + :id => 'm1.small', + :name => 'Small Instance', + :bits => 32, + :cores => 1, + :disk => 160, + :ram => 1740.8, + :ebs_optimized_available => false, + :instance_store_volumes => 1 + }, + { + :id => 'm1.medium', + :name => 'Medium Instance', + :bits => 32, + :cores => 2, + :disk => 400, + :ram => 3750, + :ebs_optimized_available => false, + :instance_store_volumes => 1 + }, + { + :id => 'm1.large', + :name => 'Large Instance', + :bits => 64, + :cores => 4, + :disk => 850, + :ram => 7680, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'm1.xlarge', + :name => 'Extra Large Instance', + :bits => 64, + :cores => 8, + :disk => 1690, + :ram => 15360, + :ebs_optimized_available => true, + :instance_store_volumes => 4 + }, + { + :id => 'c1.medium', + :bits => 32, + :cores => 5, + :disk => 350, + :name => 'High-CPU Medium', + :ram => 1740.8, + :ebs_optimized_available => false, + :instance_store_volumes => 1 + }, + { + :id => 'c1.xlarge', + :name => 'High-CPU Extra Large', + :bits => 64, + :cores => 20, + :disk => 1690, + :ram => 7168, + :ebs_optimized_available => true, + :instance_store_volumes => 4 + }, + { + :id => 'c3.large', + :name => 'C3 Large', + :bits => 64, + :cores => 7, + :disk => 32, + :ram => 3750, + :ebs_optimized_available => false, + :instance_store_volumes => 2 + }, + { + :id => 'c3.xlarge', + :name => 'C3 Extra Large', + :bits => 64, + :cores => 14, + :disk => 80, + :ram => 7168, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'c3.2xlarge', + :name => 'C3 Double Extra Large', + :bits => 64, + :cores => 28, + :disk => 160, + :ram => 15360, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'c3.4xlarge', + :name => 'C3 Quadruple Extra Large', + :bits => 64, + :cores => 55, + :disk => 320, + :ram => 30720, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'c3.8xlarge', + :name => 'C3 Eight Extra Large', + :bits => 64, + :cores => 108, + :disk => 640, + :ram => 61440, + :ebs_optimized_available => false, + :instance_store_volumes => 2 + }, + { + :id => 'g2.2xlarge', + :name => 'GPU Double Extra Large', + :bits => 64, + :cores => 26, + :disk => 60, + :ram => 15360, + :ebs_optimized_available => true, + :instance_store_volumes => 0 + }, + { + :id => 'hs1.8xlarge', + :name => 'High Storage Eight Extra Large', + :bits => 64, + :cores => 35, + :disk => 50331648, + :ram => 119808, + :ebs_optimized_available => false, + :instance_store_volumes => 24 + }, + { + :id => 'm2.xlarge', + :name => 'High-Memory Extra Large', + :bits => 64, + :cores => 6.5, + :disk => 420, + :ram => 17510.4, + :ebs_optimized_available => false, + :instance_store_volumes => 1 + }, + { + :id => 'm2.2xlarge', + :name => 'High Memory Double Extra Large', + :bits => 64, + :cores => 13, + :disk => 850, + :ram => 35020.8, + :ebs_optimized_available => true, + :instance_store_volumes => 1 + }, + { + :id => 'm2.4xlarge', + :name => 'High Memory Quadruple Extra Large', + :bits => 64, + :cores => 26, + :disk => 1690, + :ram => 70041.6, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'cr1.8xlarge', + :name => 'High Memory Eight Extra Large', + :bits => 64, + :cores => 88, + :disk => 240, + :ram => 249856, + :ebs_optimized_available => false, + :instance_store_volumes => 2 + }, + { + :id => 'm3.medium', + :name => 'M3 Medium', + :bits => 64, + :cores => 3, + :disk => 4, + :ram => 3840, + :ebs_optimized_available => false, + :instance_store_volumes => 0 + }, + { + :id => 'm3.large', + :name => 'M3 Large', + :bits => 64, + :cores => 6.5, + :disk => 32, + :ram => 7168, + :ebs_optimized_available => false, + :instance_store_volumes => 1 + }, + { + :id => 'm3.xlarge', + :name => 'M3 Extra Large', + :bits => 64, + :cores => 13, + :disk => 80, + :ram => 15360, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'm3.2xlarge', + :name => 'M3 Double Extra Large', + :bits => 64, + :cores => 26, + :disk => 160, + :ram => 30720, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => "hi1.4xlarge", + :name => "High I/O Quadruple Extra Large Instance", + :bits => 64, + :cores => 35, + :disk => 2048, + :ram => 61952, + :ebs_optimized_available => false, + :instance_store_volumes => 2 + }, + { + :id => 'cc1.4xlarge', + :name => 'Cluster Compute Quadruple Extra Large', + :bits => 64, + :cores => 33.5, + :disk => 1690, + :ram => 23552, + :ebs_optimized_available => false, + :instance_store_volumes => 0 + }, + { + :id => 'cc2.8xlarge', + :name => 'Cluster Compute Eight Extra Large', + :bits => 64, + :cores => 88, + :disk => 3370, + :ram => 61952, + :ebs_optimized_available => false, + :instance_store_volumes => 4 + }, + { + :id => 'cg1.4xlarge', + :name => 'Cluster GPU Quadruple Extra Large', + :bits => 64, + :cores => 33.5, + :disk => 1690, + :ram => 22528, + :ebs_optimized_available => false, + :instance_store_volumes => 2 + }, + { + :id => 'i2.xlarge', + :name => 'I2 Extra Large', + :bits => 64, + :cores => 14, + :disk => 800, + :ram => 31232, + :ebs_optimized_available => true, + :instance_store_volumes => 1 + }, + { + :id => 'i2.2xlarge', + :name => 'I2 Double Extra Large', + :bits => 64, + :cores => 27, + :disk => 1600, + :ram => 62464, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + }, + { + :id => 'i2.4xlarge', + :name => 'I2 Quadruple Extra Large', + :bits => 64, + :cores => 53, + :disk => 3200, + :ram => 124928, + :ebs_optimized_available => true, + :instance_store_volumes => 4 + }, + { + :id => 'i2.8xlarge', + :name => 'I2 Eight Extra Large', + :bits => 64, + :cores => 104, + :disk => 6400, + :ram => 249856, + :ebs_optimized_available => false, + :instance_store_volumes => 8 + }, + { + :id => "r3.large", + :name => "R3 Large", + :bits => 64, + :cores => 2, + :ram => 15360, + :disk => 32, + :ebs_optimized_available => true, + :instance_store_volumes => 1 + }, + { + :id => "r3.xlarge", + :name => "R3 Extra Large", + :bits => 64, + :cores => 4, + :ram => 31232, + :disk => 80, + :ebs_optimized_available => true, + :instance_store_volumes => 1 + }, + { + :id => "r3.2xlarge", + :name => "R3 Double Extra Large", + :bits => 64, + :cores => 8, + :ram => 62464, + :disk => 160, + :ebs_optimized_available => true, + :instance_store_volumes => 1 + }, + { + :id => "r3.4xlarge", + :name => "R3 Quadruple Extra Large", + :bits => 64, + :cores => 16, + :ram => 124928, + :disk => 320, + :ebs_optimized_available => true, + :instance_store_volumes => 1 + }, + { + :id => "r3.8xlarge", + :name => "R3 Eight Extra Large", + :bits => 64, + :cores => 32, + :ram => 249856, + :disk => 640, + :ebs_optimized_available => true, + :instance_store_volumes => 2 + } + ] + + class Flavors < Fog::Collection + model Fog::Compute::AWS::Flavor + + # Returns an array of all flavors that have been created + # + # Aws.flavors.all + # + # ==== Returns + # + # Returns an array of all available instances and their general information + # + #>> Aws.flavors.all + # , + # , + # , + # , + # , + # , + # , + # , + # , + # , + # , + # , + # , + # , + # + # ] + # > + # + + def all + load(Fog::Compute::AWS::FLAVORS) + self + end + + # Used to retrieve a flavor + # flavor_id is required to get the associated flavor information. + # flavors available currently: + # + # t1.micro + # m1.small, m1.medium, m1.large, m1.xlarge + # c1.medium, c1.xlarge + # c3.large, c3.xlarge, c3.2xlarge, c3.4xlarge, c3.8xlarge + # g2.2xlarge + # hs1.8xlarge + # m2.xlarge, m2.2xlarge, m2.4xlarge + # m3.xlarge, m3.2xlarge + # cr1.8xlarge + # cc1.4xlarge + # cc2.8xlarge + # cg1.4xlarge + # i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge + # + # You can run the following command to get the details: + # Aws.flavors.get("t1.micro") + # + # ==== Returns + # + #>> Aws.flavors.get("t1.micro") + # + # + + def get(flavor_id) + self.class.new(:service => service).all.find {|flavor| flavor.id == flavor_id} + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/image.rb b/lib/fog/aws/models/compute/image.rb new file mode 100644 index 000000000..a5c1675f3 --- /dev/null +++ b/lib/fog/aws/models/compute/image.rb @@ -0,0 +1,45 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Image < Fog::Model + identity :id, :aliases => 'imageId' + + attribute :architecture + attribute :block_device_mapping, :aliases => 'blockDeviceMapping' + attribute :description + attribute :location, :aliases => 'imageLocation' + attribute :owner_id, :aliases => 'imageOwnerId' + attribute :owner_alias, :aliases => 'imageOwnerAlias' + attribute :state, :aliases => 'imageState' + attribute :type, :aliases => 'imageType' + attribute :is_public, :aliases => 'isPublic' + attribute :kernel_id, :aliases => 'kernelId' + attribute :platform + attribute :product_codes, :aliases => 'productCodes' + attribute :ramdisk_id, :aliases => 'ramdiskId' + attribute :root_device_type, :aliases => 'rootDeviceType' + attribute :root_device_name, :aliases => 'rootDeviceName' + attribute :tags, :aliases => 'tagSet' + attribute :name + attribute :virtualization_type, :aliases => 'virtualizationType' + + def deregister(delete_snapshot = false) + service.deregister_image(id) + + if(delete_snapshot && root_device_type == "ebs") + block_device = block_device_mapping.find {|block_device| block_device['deviceName'] == root_device_name} + service.snapshots.new(:id => block_device['snapshotId']).destroy + else + true + end + end + + def ready? + state == 'available' + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/images.rb b/lib/fog/aws/models/compute/images.rb new file mode 100644 index 000000000..03bd093b4 --- /dev/null +++ b/lib/fog/aws/models/compute/images.rb @@ -0,0 +1,59 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/image' + +module Fog + module Compute + class Aws + class Images < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::Image + + # Creates a new Amazon machine image + # + # Aws.images.new + # + # ==== Returns + # + # Returns the details of the new image + # + #>> Aws.images.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + def all(filters_arg = filters) + filters = filters_arg + data = service.describe_images(filters).body + load(data['imagesSet']) + end + + def get(image_id) + if image_id + self.class.new(:service => service).all('image-id' => image_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/internet_gateway.rb b/lib/fog/aws/models/compute/internet_gateway.rb new file mode 100644 index 000000000..b90623262 --- /dev/null +++ b/lib/fog/aws/models/compute/internet_gateway.rb @@ -0,0 +1,78 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class InternetGateway < Fog::Model + identity :id, :aliases => 'internetGatewayId' + attribute :attachment_set, :aliases => 'attachmentSet' + attribute :tag_set, :aliases => 'tagSet' + + def initialize(attributes={}) + super + end + + # Attaches an existing internet gateway + # + # internet_gateway.attach(igw-id, vpc-id) + # + # ==== Returns + # + # True or false depending on the result + # + def attach(vpc_id) + requires :id + service.attach_internet_gateway(id, vpc_id) + reload + end + + # Detaches an existing internet gateway + # + # internet_gateway.detach(igw-id, vpc-id) + # + # ==== Returns + # + # True or false depending on the result + # + def detach(vpc_id) + requires :id + service.detach_internet_gateway(id, vpc_id) + reload + end + + # Removes an existing internet gateway + # + # internet_gateway.destroy + # + # ==== Returns + # + # True or false depending on the result + # + def destroy + requires :id + + service.delete_internet_gateway(id) + true + end + + # Create an internet gateway + # + # >> g = Aws.internet_gateways.new() + # >> g.save + # + # == Returns: + # + # requestId and a internetGateway object + # + def save + data = service.create_internet_gateway.body['internetGatewaySet'].first + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + true + + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/internet_gateways.rb b/lib/fog/aws/models/compute/internet_gateways.rb new file mode 100644 index 000000000..0fd1ae1ec --- /dev/null +++ b/lib/fog/aws/models/compute/internet_gateways.rb @@ -0,0 +1,87 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/internet_gateway' + +module Fog + module Compute + class Aws + class InternetGateways < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::InternetGateway + + # Creates a new internet gateway + # + # Aws.internet_gateways.new + # + # ==== Returns + # + # Returns the details of the new InternetGateway + # + #>> Aws.internet_gateways.new + #=> + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all InternetGateways that have been created + # + # Aws.internet_gateways.all + # + # ==== Returns + # + # Returns an array of all InternetGateways + # + #>> Aws.internet_gateways.all + #"vpc-some-id", "state"=>"available"}, + #tag_set={} + #> + #] + #> + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.warning("all with #{filters_arg.class} param is deprecated, use all('internet-gateway-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'internet-gateway-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_internet_gateways(filters).body + load(data['internetGatewaySet']) + end + + # Used to retrieve an InternetGateway + # + # You can run the following command to get the details: + # Aws.internet_gateways.get("igw-12345678") + # + # ==== Returns + # + #>> Aws.internet_gateways.get("igw-12345678") + #=> "vpc-12345678", "state"=>"available"}, + #tag_set={} + #> + # + + def get(internet_gateway_id) + if internet_gateway_id + self.class.new(:service => service).all('internet-gateway-id' => internet_gateway_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/key_pair.rb b/lib/fog/aws/models/compute/key_pair.rb new file mode 100644 index 000000000..8206d4451 --- /dev/null +++ b/lib/fog/aws/models/compute/key_pair.rb @@ -0,0 +1,53 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class KeyPair < Fog::Model + identity :name, :aliases => 'keyName' + + attribute :fingerprint, :aliases => 'keyFingerprint' + attribute :private_key, :aliases => 'keyMaterial' + + attr_accessor :public_key + + def destroy + requires :name + + service.delete_key_pair(name) + true + end + + def save + requires :name + + data = if public_key + service.import_key_pair(name, public_key).body + else + service.create_key_pair(name).body + end + new_attributes = data.reject {|key,value| !['keyFingerprint', 'keyMaterial', 'keyName'].include?(key)} + merge_attributes(new_attributes) + true + end + + def write(path="#{ENV['HOME']}/.ssh/fog_#{Fog.credential.to_s}_#{name}.pem") + if writable? + split_private_key = private_key.split(/\n/) + File.open(path, "w") do |f| + split_private_key.each {|line| f.puts line} + f.chmod 0600 + end + "Key file built: #{path}" + else + "Invalid private key" + end + end + + def writable? + !!(private_key && ENV.key?('HOME')) + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/key_pairs.rb b/lib/fog/aws/models/compute/key_pairs.rb new file mode 100644 index 000000000..586479b8a --- /dev/null +++ b/lib/fog/aws/models/compute/key_pairs.rb @@ -0,0 +1,84 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/key_pair' + +module Fog + module Compute + class Aws + class KeyPairs < Fog::Collection + attribute :filters + attribute :key_name + + model Fog::Compute::AWS::KeyPair + + # Used to create a key pair. There are 3 arguments and only name is required. You can generate a new key_pair as follows: + # Aws.key_pairs.create(:name => "test", :fingerprint => "123", :private_key => '234234') + # + # ==== Returns + # + # + # + # The key_pair can be retrieved by running Aws.key_pairs.get("test"). See get method below. + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all key pairs that have been created + # + # Aws.key_pairs.all + # + # ==== Returns + # + # + # ] + #> + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters_arg.class} param is deprecated, use all('key-name' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'key-name' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_key_pairs(filters).body + load(data['keySet']) + end + + # Used to retrieve a key pair that was created with the Aws.key_pairs.create method. + # The name is required to get the associated key_pair information. + # + # You can run the following command to get the details: + # Aws.key_pairs.get("test") + # + # ==== Returns + # + #>> Aws.key_pairs.get("test") + # + # + + def get(key_name) + if key_name + self.class.new(:service => service).all('key-name' => key_name).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/network_acl.rb b/lib/fog/aws/models/compute/network_acl.rb new file mode 100644 index 000000000..60d9111a0 --- /dev/null +++ b/lib/fog/aws/models/compute/network_acl.rb @@ -0,0 +1,180 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class NetworkAcl < Fog::Model + ICMP = 1 + TCP = 6 + UDP = 17 + + identity :network_acl_id, :aliases => 'networkAclId' + attribute :vpc_id, :aliases => 'vpcId' + attribute :default + attribute :entries, :aliases => 'entrySet' + attribute :associations, :aliases => 'associationSet' + attribute :tags, :aliases => 'tagSet' + + # Add an inbound rule, shortcut method for #add_rule + def add_inbound_rule(rule_number, protocol, rule_action, cidr_block, options = {}) + add_rule(rule_number, protocol, rule_action, cidr_block, false, options) + end + + # Add an outbound rule, shortcut method for #add_rule + def add_outbound_rule(rule_number, protocol, rule_action, cidr_block, options = {}) + add_rule(rule_number, protocol, rule_action, cidr_block, true, options) + end + + # Add a new rule + # + # network_acl.add_rule(100, Fog::Compute::AWS::NetworkAcl::TCP, 'allow', '0.0.0.0/0', true, 'PortRange.From' => 22, 'PortRange.To' => 22) + # + # ==== Parameters + # * rule_number<~Integer> - The rule number for the entry, between 100 and 32766 + # * protocol<~Integer> - The IP protocol to which the rule applies. You can use -1 to mean all protocols. + # * rule_action<~String> - Allows or denies traffic that matches the rule. (either allow or deny) + # * cidr_block<~String> - The CIDR range to allow or deny + # * egress<~Boolean> - Indicates whether this rule applies to egress traffic from the subnet (true) or ingress traffic to the subnet (false). + # * options<~Hash>: + # * 'Icmp.Code' - ICMP code, required if protocol is 1 + # * 'Icmp.Type' - ICMP type, required if protocol is 1 + # * 'PortRange.From' - The first port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # * 'PortRange.To' - The last port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # + # ==== Returns + # + # True or false depending on the result + # + def add_rule(rule_number, protocol, rule_action, cidr_block, egress, options = {}) + requires :network_acl_id + + service.create_network_acl_entry(network_acl_id, rule_number, protocol, rule_action, cidr_block, egress, options) + true + end + + # Remove an inbound rule, shortcut method for #remove_rule + def remove_inbound_rule(rule_number) + remove_rule(rule_number, false) + end + + # Remove an outbound rule, shortcut method for #remove_rule + def remove_outbound_rule(rule_number) + remove_rule(rule_number, true) + end + + # Update a specific rule number + # + # network_acl.remove_rule(100, true) + # + # ==== Parameters + # * rule_number<~Integer> - The rule number for the entry, between 100 and 32766 + # * egress<~Boolean> - Indicates whether this rule applies to egress traffic from the subnet (true) or ingress traffic to the subnet (false). + # + # ==== Returns + # + # True or false depending on the result + # + def remove_rule(rule_number, egress) + requires :network_acl_id + + service.delete_network_acl_entry(network_acl_id, rule_number, egress) + true + end + + # Update an inbound rule, shortcut method for #update_rule + def update_inbound_rule(rule_number, protocol, rule_action, cidr_block, options = {}) + update_rule(rule_number, protocol, rule_action, cidr_block, false, options) + end + + # Update an outbound rule, shortcut method for #update_rule + def update_outbound_rule(rule_number, protocol, rule_action, cidr_block, options = {}) + update_rule(rule_number, protocol, rule_action, cidr_block, true, options) + end + + # Update a specific rule number + # + # network_acl.update_rule(100, Fog::Compute::AWS::NetworkAcl::TCP, 'allow', '0.0.0.0/0', true, 'PortRange.From' => 22, 'PortRange.To' => 22) + # + # ==== Parameters + # * rule_number<~Integer> - The rule number for the entry, between 100 and 32766 + # * protocol<~Integer> - The IP protocol to which the rule applies. You can use -1 to mean all protocols. + # * rule_action<~String> - Allows or denies traffic that matches the rule. (either allow or deny) + # * cidr_block<~String> - The CIDR range to allow or deny + # * egress<~Boolean> - Indicates whether this rule applies to egress traffic from the subnet (true) or ingress traffic to the subnet (false). + # * options<~Hash>: + # * 'Icmp.Code' - ICMP code, required if protocol is 1 + # * 'Icmp.Type' - ICMP type, required if protocol is 1 + # * 'PortRange.From' - The first port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # * 'PortRange.To' - The last port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # + # ==== Returns + # + # True or false depending on the result + # + def update_rule(rule_number, protocol, rule_action, cidr_block, egress, options = {}) + requires :network_acl_id + + service.replace_network_acl_entry(network_acl_id, rule_number, protocol, rule_action, cidr_block, egress, options) + true + end + + # Associate a subnet with this network ACL + # + # network_acl.associate_with(subnet) + # + # ==== Parameters + # * subnet<~Subnet> - Subnet object to associate with this network ACL + # + # ==== Returns + # + # True or false depending on the result + # + def associate_with(subnet) + requires :network_acl_id + + # We have to manually find out the network ACL the subnet is currently associated with + old_id = service.network_acls.all('association.subnet-id' => subnet.subnet_id).first.associations.find { |a| a['subnetId'] == subnet.subnet_id }['networkAclAssociationId'] + service.replace_network_acl_association(old_id, network_acl_id) + true + end + + # Removes an existing network ACL + # + # network_acl.destroy + # + # ==== Returns + # + # True or false depending on the result + # + def destroy + requires :network_acl_id + + service.delete_network_acl(network_acl_id) + true + end + + # Create a network ACL + # + # >> g = Aws.network_acls.new(:vpc_id => 'vpc-abcdefgh') + # >> g.save + def save + requires :vpc_id + data = service.create_network_acl(vpc_id).body['networkAcl'] + new_attributes = data.reject { |key,value| key == 'tagSet' } + merge_attributes(new_attributes) + + if tags = self.tags + # expect eventual consistency + Fog.wait_for { self.reload rescue nil } + service.create_tags( + self.identity, + tags + ) + end + + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/network_acls.rb b/lib/fog/aws/models/compute/network_acls.rb new file mode 100644 index 000000000..f00dce4ec --- /dev/null +++ b/lib/fog/aws/models/compute/network_acls.rb @@ -0,0 +1,136 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/network_acl' + +module Fog + module Compute + class Aws + class NetworkAcls < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::NetworkAcl + + # Creates a new network ACL + # + # Aws.network_acls.new + # + # ==== Returns + # + # Returns the details of the new network ACL + # + #>> + # + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all network ACLs that have been created + # + # Aws.network_acls.all + # + # ==== Returns + # + # Returns an array of all network ACLs + # + #>> Aws.network_acls.all + # {}, + # "portRange" => {}, + # "ruleNumber" => 32767, + # "protocol" => -1, + # "ruleAction" => "deny", + # "egress" => false, + # "cidrBlock" => "0.0.0.0/0" + # }, + # { + # "icmpTypeCode" => {}, + # "portRange" => {}, + # "ruleNumber" => 32767, + # "protocol" => -1, + # "ruleAction" => "deny", + # "egress" => true, + # "cidrBlock" => "0.0.0.0/0" + # } + # ], + # associations=[ + # { + # "networkAclAssociationId" => "aclassoc-abcdefgh", + # "networkAclId" => "acl-abcdefgh", + # "subnetId" => "subnet-abcdefgh" + # } + # ], + # tags={} + # > + # ] + # > + # + def all(filters_arg = filters) + filters = filters_arg + data = service.describe_network_acls(filters).body + load(data['networkAclSet']) + end + + # Used to retrieve a network interface + # network interface id is required to get any information + # + # You can run the following command to get the details: + # Aws.network_interfaces.get("eni-11223344") + # + # ==== Returns + # + #>> Aws.network_acls.get("acl-abcdefgh") + # {}, + # "portRange" => {}, + # "ruleNumber" => 32767, + # "protocol" => -1, + # "ruleAction" => "deny", + # "egress" => false, + # "cidrBlock" => "0.0.0.0/0" + # }, + # { + # "icmpTypeCode" => {}, + # "portRange" => {}, + # "ruleNumber" => 32767, + # "protocol" => -1, + # "ruleAction" => "deny", + # "egress" => true, + # "cidrBlock" => "0.0.0.0/0" + # } + # ], + # associations=[ + # { + # "networkAclAssociationId" => "aclassoc-abcdefgh", + # "networkAclId" => "acl-abcdefgh", + # "subnetId" => "subnet-abcdefgh" + # } + # ], + # tags={} + # > + def get(nacl_id) + self.class.new(:service => service).all('network-acl-id' => nacl_id).first if nacl_id + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/network_interface.rb b/lib/fog/aws/models/compute/network_interface.rb new file mode 100644 index 000000000..40092fe13 --- /dev/null +++ b/lib/fog/aws/models/compute/network_interface.rb @@ -0,0 +1,73 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class NetworkInterface < Fog::Model + identity :network_interface_id, :aliases => 'networkInterfaceId' + attribute :state + attribute :request_id, :aliases => 'requestId' + attribute :network_interface_id, :aliases => 'networkInterfaceId' + attribute :subnet_id, :aliases => 'subnetId' + attribute :vpc_id, :aliases => 'vpcId' + attribute :availability_zone, :aliases => 'availabilityZone' + attribute :description, :aliases => 'description' + attribute :owner_id, :aliases => 'ownerId' + attribute :requester_id, :aliases => 'requesterId' + attribute :requester_managed, :aliases => 'requesterManaged' + attribute :status, :aliases => 'status' + attribute :mac_address, :aliases => 'macAddress' + attribute :private_ip_address, :aliases => 'privateIpAddress' + attribute :private_ip_addresses, :aliases => 'privateIpAddresses' + attribute :private_dns_name, :aliases => 'privateDnsName' + attribute :source_dest_check, :aliases => 'sourceDestCheck' + attribute :group_set, :aliases => 'groupSet' + attribute :attachment, :aliases => 'attachment' + attribute :association, :aliases => 'association' + attribute :tag_set, :aliases => 'tagSet' + + # Removes an existing network interface + # + # network_interface.destroy + # + # ==== Returns + # + # True or false depending on the result + # + + def destroy + requires :network_interface_id + + service.delete_network_interface(network_interface_id) + true + end + + # Create a network_interface + # + # >> g = Aws.network_interfaces.new(:subnet_id => "subnet-someId", options) + # >> g.save + # + # options is an optional hash which may contain 'PrivateIpAddress', 'Description', 'GroupSet' + # + # == Returns: + # + # requestId and a networkInterface object + # + + def save + requires :subnet_id + options = { + 'PrivateIpAddress' => private_ip_address, + 'Description' => description, + 'GroupSet' => group_set, + } + options.delete_if {|key, value| value.nil?} + data = service.create_network_interface(subnet_id, options).body['networkInterface'] + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/network_interfaces.rb b/lib/fog/aws/models/compute/network_interfaces.rb new file mode 100644 index 000000000..416ea9db3 --- /dev/null +++ b/lib/fog/aws/models/compute/network_interfaces.rb @@ -0,0 +1,133 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/network_interface' + +module Fog + module Compute + class Aws + class NetworkInterfaces < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::NetworkInterface + + # Creates a new network interface + # + # Aws.network_interfaces.new + # + # ==== Returns + # + # Returns the details of the new network interface + # + #>> Aws.network_interfaces.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all network interfaces that have been created + # + # Aws.network_interfaces.all + # + # ==== Returns + # + # Returns an array of all network interfaces + # + #>> Aws.network_interfaves.all + # + # ] + # > + # + + def all(filters_arg = filters) + filters = filters_arg + data = service.describe_network_interfaces(filters).body + load(data['networkInterfaceSet']) + end + + # Used to retrieve a network interface + # network interface id is required to get any information + # + # You can run the following command to get the details: + # Aws.network_interfaces.get("eni-11223344") + # + # ==== Returns + # + #>> Aws.NetworkInterface.get("eni-11223344") + # + # + + def get(nic_id) + if nic_id + self.class.new(:service => service).all('network-interface-id' => nic_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/route_table.rb b/lib/fog/aws/models/compute/route_table.rb new file mode 100755 index 000000000..3d03a66d1 --- /dev/null +++ b/lib/fog/aws/models/compute/route_table.rb @@ -0,0 +1,66 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class RouteTable < Fog::Model + identity :id, :aliases => 'routeTableId' + + attribute :vpc_id, :aliases => 'vpcId' + attribute :routes, :aliases => 'routeSet' + attribute :associations, :aliases => 'associationSet' + attribute :tags, :aliases => 'tagSet' + + + def initialize(attributes={}) + super + end + + # Remove an existing route table + # + # route_tables.destroy + # + # ==== Returns + # + # True or false depending on the result + # + + def destroy + requires :id + + service.delete_route_table(id) + true + end + + # Create a route table + # + # >> routetable = connection.route_tables.new + # >> routetable.save + # + # == Returns: + # + # True or an exception depending on the result. Keep in mind that this *creates* a new route table. + # + + def save + requires :vpc_id + + data = service.create_route_table(vpc_id).body['routeTable'].first + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + true + end + + private + + def associationSet=(new_association_set) + merge_attributes(new_association_set.first || {}) + end + + def routeSet=(new_route_set) + merge_attributes(new_route_set || {}) + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/route_tables.rb b/lib/fog/aws/models/compute/route_tables.rb new file mode 100755 index 000000000..825a624c1 --- /dev/null +++ b/lib/fog/aws/models/compute/route_tables.rb @@ -0,0 +1,88 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/route_table' + +module Fog + module Compute + class Aws + class RouteTables < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::RouteTable + + # Creates a new route table + # + # Aws.route_tables.new + # + # ==== Returns + # + # Returns the details of the new route table + # + #>> Aws.route_tables.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all route tables that have been created + # + # Aws.route_tables.all + # + # ==== Returns + # + # Returns an array of all route tables + # + #>> Aws.route_tables.all + # + # ] + # > + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.warning("all with #{filters_arg.class} param is deprecated, use all('route-table-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'route-table-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_route_tables(filters).body + load(data['routeTableSet']) + end + + # Used to retrieve a route table + # route_table_id is required to get the associated route table information. + # + # You can run the following command to get the details: + # Aws.route_tables.get("rtb-41e8552f") + # + # ==== Returns + # + #>> Aws.route_tables.get("rtb-41e8552f") + # + # + + def get(route_table_id) + if route_table_id + self.class.new(:service => service).all('route-table-id' => route_table_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/security_group.rb b/lib/fog/aws/models/compute/security_group.rb new file mode 100644 index 000000000..51ed77bb3 --- /dev/null +++ b/lib/fog/aws/models/compute/security_group.rb @@ -0,0 +1,322 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class SecurityGroup < Fog::Model + identity :name, :aliases => 'groupName' + attribute :description, :aliases => 'groupDescription' + attribute :group_id, :aliases => 'groupId' + attribute :ip_permissions, :aliases => 'ipPermissions' + attribute :ip_permissions_egress, :aliases => 'ipPermissionsEgress' + attribute :owner_id, :aliases => 'ownerId' + attribute :vpc_id, :aliases => 'vpcId' + attribute :tags, :aliases => 'tagSet' + + # Authorize access by another security group + # + # >> g = Aws.security_groups.all(:description => "something").first + # >> g.authorize_group_and_owner("some_group_name", "1234567890") + # + # == Parameters: + # group:: + # The name of the security group you're granting access to. + # + # owner:: + # The owner id for security group you're granting access to. + # + # == Returns: + # + # An excon response object representing the result + # + # "some-id-string", + # "return"=>true}, + # headers{"Transfer-Encoding"=>"chunked", + # "Date"=>"Mon, 27 Dec 2010 22:12:57 GMT", + # "Content-Type"=>"text/xml;charset=UTF-8", + # "Server"=>"AmazonEC2"} + # + + def authorize_group_and_owner(group, owner = nil) + Fog::Logger.deprecation("authorize_group_and_owner is deprecated, use authorize_port_range with :group option instead") + + requires_one :name, :group_id + + service.authorize_security_group_ingress( + name, + 'GroupId' => group_id, + 'SourceSecurityGroupName' => group, + 'SourceSecurityGroupOwnerId' => owner + ) + end + + # Authorize a new port range for a security group + # + # >> g = Aws.security_groups.all(:description => "something").first + # >> g.authorize_port_range(20..21) + # + # == Parameters: + # range:: + # A Range object representing the port range you want to open up. E.g., 20..21 + # + # options:: + # A hash that can contain any of the following keys: + # :cidr_ip (defaults to "0.0.0.0/0") + # :group - ("account:group_name" or "account:group_id"), cannot be used with :cidr_ip + # :ip_protocol (defaults to "tcp") + # + # == Returns: + # + # An excon response object representing the result + # + # "some-id-string", + # "return"=>true}, + # headers{"Transfer-Encoding"=>"chunked", + # "Date"=>"Mon, 27 Dec 2010 22:12:57 GMT", + # "Content-Type"=>"text/xml;charset=UTF-8", + # "Server"=>"AmazonEC2"} + # + + def authorize_port_range(range, options = {}) + requires_one :name, :group_id + + ip_permission = { + 'FromPort' => range.min, + 'ToPort' => range.max, + 'IpProtocol' => options[:ip_protocol] || 'tcp' + } + + if options[:group].nil? + ip_permission['IpRanges'] = [ + { 'CidrIp' => options[:cidr_ip] || '0.0.0.0/0' } + ] + else + ip_permission['Groups'] = [ + group_info(options[:group]) + ] + end + + service.authorize_security_group_ingress( + name, + 'GroupId' => group_id, + 'IpPermissions' => [ ip_permission ] + ) + end + + # Removes an existing security group + # + # security_group.destroy + # + # ==== Returns + # + # True or false depending on the result + # + + def destroy + requires_one :name, :group_id + + if group_id.nil? + service.delete_security_group(name) + else + service.delete_security_group(nil, group_id) + end + true + end + + # Revoke access by another security group + # + # >> g = Aws.security_groups.all(:description => "something").first + # >> g.revoke_group_and_owner("some_group_name", "1234567890") + # + # == Parameters: + # group:: + # The name of the security group you're revoking access to. + # + # owner:: + # The owner id for security group you're revoking access access to. + # + # == Returns: + # + # An excon response object representing the result + # + # "some-id-string", + # "return"=>true}, + # headers{"Transfer-Encoding"=>"chunked", + # "Date"=>"Mon, 27 Dec 2010 22:12:57 GMT", + # "Content-Type"=>"text/xml;charset=UTF-8", + # "Server"=>"AmazonEC2"} + # + + def revoke_group_and_owner(group, owner = nil) + Fog::Logger.deprecation("revoke_group_and_owner is deprecated, use revoke_port_range with :group option instead") + + requires_one :name, :group_id + + service.revoke_security_group_ingress( + name, + 'GroupId' => group_id, + 'SourceSecurityGroupName' => group, + 'SourceSecurityGroupOwnerId' => owner + ) + end + + # Revoke an existing port range for a security group + # + # >> g = Aws.security_groups.all(:description => "something").first + # >> g.revoke_port_range(20..21) + # + # == Parameters: + # range:: + # A Range object representing the port range you want to open up. E.g., 20..21 + # + # options:: + # A hash that can contain any of the following keys: + # :cidr_ip (defaults to "0.0.0.0/0") + # :group - ("account:group_name" or "account:group_id"), cannot be used with :cidr_ip + # :ip_protocol (defaults to "tcp") + # + # == Returns: + # + # An excon response object representing the result + # + # "some-id-string", + # "return"=>true}, + # headers{"Transfer-Encoding"=>"chunked", + # "Date"=>"Mon, 27 Dec 2010 22:12:57 GMT", + # "Content-Type"=>"text/xml;charset=UTF-8", + # "Server"=>"AmazonEC2"} + # + + def revoke_port_range(range, options = {}) + requires_one :name, :group_id + + ip_permission = { + 'FromPort' => range.min, + 'ToPort' => range.max, + 'IpProtocol' => options[:ip_protocol] || 'tcp' + } + + if options[:group].nil? + ip_permission['IpRanges'] = [ + { 'CidrIp' => options[:cidr_ip] || '0.0.0.0/0' } + ] + else + ip_permission['Groups'] = [ + group_info(options[:group]) + ] + end + + service.revoke_security_group_ingress( + name, + 'GroupId' => group_id, + 'IpPermissions' => [ ip_permission ] + ) + end + + # Reload a security group + # + # >> g = Aws.security_groups.get(:name => "some_name") + # >> g.reload + # + # == Returns: + # + # Up to date model or an exception + + def reload + if group_id.nil? + super + service.delete_security_group(name) + else + requires :group_id + + data = begin + collection.get_by_id(group_id) + rescue Excon::Errors::SocketError + nil + end + + return unless data + + merge_attributes(data.attributes) + self + end + end + + + # Create a security group + # + # >> g = Aws.security_groups.new(:name => "some_name", :description => "something") + # >> g.save + # + # == Returns: + # + # True or an exception depending on the result. Keep in mind that this *creates* a new security group. + # As such, it yields an InvalidGroup.Duplicate exception if you attempt to save an existing group. + # + + def save + requires :description, :name + data = service.create_security_group(name, description, vpc_id).body + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + + if tags = self.tags + # expect eventual consistency + Fog.wait_for { self.reload rescue nil } + service.create_tags( + self.group_id, + tags + ) + end + + true + end + + private + + # + # +group_arg+ may be a string or a hash with one key & value. + # + # If group_arg is a string, it is assumed to be the group name, + # and the UserId is assumed to be self.owner_id. + # + # The "account:group" form is deprecated. + # + # If group_arg is a hash, the key is the UserId and value is the group. + def group_info(group_arg) + if Hash === group_arg + account = group_arg.keys.first + group = group_arg.values.first + elsif group_arg.match(/:/) + account, group = group_arg.split(':') + Fog::Logger.deprecation("'account:group' argument is deprecated. Use {account => group} or just group instead") + else + requires :owner_id + account = owner_id + group = group_arg + end + + info = { 'UserId' => account } + + if group.start_with?("sg-") + # we're dealing with a security group id + info['GroupId'] = group + else + # this has to be a security group name + info['GroupName'] = group + end + + info + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/security_groups.rb b/lib/fog/aws/models/compute/security_groups.rb new file mode 100644 index 000000000..35159ba3e --- /dev/null +++ b/lib/fog/aws/models/compute/security_groups.rb @@ -0,0 +1,117 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/security_group' + +module Fog + module Compute + class Aws + class SecurityGroups < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::SecurityGroup + + # Creates a new security group + # + # Aws.security_groups.new + # + # ==== Returns + # + # Returns the details of the new image + # + #>> Aws.security_groups.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all security groups that have been created + # + # Aws.security_groups.all + # + # ==== Returns + # + # Returns an array of all security groups + # + #>> Aws.security_groups.all + # [{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>-1, "toPort"=>-1, "ipRanges"=>[], "ipProtocol"=>"icmp"}, {"groups"=>[{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>0, "toPort"=>65535, "ipRanges"=>[], "ipProtocol"=>"tcp"}, {"groups"=>[{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>0, "toPort"=>65535, "ipRanges"=>[], "ipProtocol"=>"udp"}], + # owner_id="312571045469" + # vpc_id=nill + # > + # ] + # > + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters_arg.class} param is deprecated, use all('group-name' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'group-name' => [*filters_arg]} + end + self.filters = filters_arg + data = service.describe_security_groups(filters).body + load(data['securityGroupInfo']) + end + + # Used to retrieve a security group + # group name is required to get the associated flavor information. + # + # You can run the following command to get the details: + # Aws.security_groups.get("default") + # + # ==== Returns + # + #>> Aws.security_groups.get("default") + # [{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>-1, "toPort"=>-1, "ipRanges"=>[], "ipProtocol"=>"icmp"}, {"groups"=>[{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>0, "toPort"=>65535, "ipRanges"=>[], "ipProtocol"=>"tcp"}, {"groups"=>[{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>0, "toPort"=>65535, "ipRanges"=>[], "ipProtocol"=>"udp"}], + # owner_id="312571045469" + # vpc_id=nil + # > + # + + def get(group_name) + if group_name + self.class.new(:service => service).all('group-name' => group_name).first + end + end + + # Used to retrieve a security group + # group id is required to get the associated flavor information. + # + # You can run the following command to get the details: + # Aws.security_groups.get_by_id("default") + # + # ==== Returns + # + #>> Aws.security_groups.get_by_id("sg-123456") + # [{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>-1, "toPort"=>-1, "ipRanges"=>[], "ipProtocol"=>"icmp"}, {"groups"=>[{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>0, "toPort"=>65535, "ipRanges"=>[], "ipProtocol"=>"tcp"}, {"groups"=>[{"groupName"=>"default", "userId"=>"312571045469"}], "fromPort"=>0, "toPort"=>65535, "ipRanges"=>[], "ipProtocol"=>"udp"}], + # owner_id="312571045469" + # > + # + + def get_by_id(group_id) + if group_id + self.class.new(:service => service).all('group-id' => group_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/server.rb b/lib/fog/aws/models/compute/server.rb new file mode 100644 index 000000000..0d8aea550 --- /dev/null +++ b/lib/fog/aws/models/compute/server.rb @@ -0,0 +1,271 @@ +require 'fog/compute/models/server' + +module Fog + module Compute + class Aws + class Server < Fog::Compute::Server + extend Fog::Deprecation + deprecate :ip_address, :public_ip_address + + identity :id, :aliases => 'instanceId' + + attr_accessor :architecture + attribute :ami_launch_index, :aliases => 'amiLaunchIndex' + attribute :associate_public_ip, :aliases => 'associatePublicIP' + attribute :availability_zone, :aliases => 'availabilityZone' + attribute :block_device_mapping, :aliases => 'blockDeviceMapping' + attribute :network_interfaces, :aliases => 'networkInterfaces' + attribute :client_token, :aliases => 'clientToken' + attribute :disable_api_termination, :aliases => 'disableApiTermination' + attribute :dns_name, :aliases => 'dnsName' + attribute :ebs_optimized, :aliases => 'ebsOptimized' + attribute :groups + attribute :flavor_id, :aliases => 'instanceType' + attribute :hypervisor + attribute :iam_instance_profile, :aliases => 'iamInstanceProfile' + attribute :image_id, :aliases => 'imageId' + attr_accessor :instance_initiated_shutdown_behavior + attribute :kernel_id, :aliases => 'kernelId' + attribute :key_name, :aliases => 'keyName' + attribute :created_at, :aliases => 'launchTime' + attribute :lifecycle, :aliases => 'instanceLifecycle' + attribute :monitoring, :squash => 'state' + attribute :placement_group, :aliases => 'groupName' + attribute :platform, :aliases => 'platform' + attribute :product_codes, :aliases => 'productCodes' + attribute :private_dns_name, :aliases => 'privateDnsName' + attribute :private_ip_address, :aliases => 'privateIpAddress' + attribute :public_ip_address, :aliases => 'ipAddress' + attribute :ramdisk_id, :aliases => 'ramdiskId' + attribute :reason + attribute :requester_id, :aliases => 'requesterId' + attribute :root_device_name, :aliases => 'rootDeviceName' + attribute :root_device_type, :aliases => 'rootDeviceType' + attribute :security_group_ids, :aliases => 'securityGroupIds' + attribute :source_dest_check, :aliases => 'sourceDestCheck' + attribute :spot_instance_request_id, :aliases => 'spotInstanceRequestId' + attribute :state, :aliases => 'instanceState', :squash => 'name' + attribute :state_reason, :aliases => 'stateReason' + attribute :subnet_id, :aliases => 'subnetId' + attribute :tenancy + attribute :tags, :aliases => 'tagSet' + attribute :user_data + attribute :virtualization_type, :aliases => 'virtualizationType' + attribute :vpc_id, :aliases => 'vpcId' + + attr_accessor :password + attr_writer :iam_instance_profile_name, :iam_instance_profile_arn + + def initialize(attributes={}) + self.groups ||= ["default"] unless (attributes[:subnet_id] || attributes[:security_group_ids] || attributes[:network_interfaces]) + self.flavor_id ||= 't1.micro' + + # Old 'connection' is renamed as service and should be used instead + prepare_service_value(attributes) + + self.image_id ||= begin + self.username ||= 'ubuntu' + case @service.instance_variable_get(:@region) # Ubuntu 10.04 LTS 64bit (EBS) + when 'ap-northeast-1' + 'ami-5e0fa45f' + when 'ap-southeast-1' + 'ami-f092eca2' + when 'ap-southeast-2' + 'ami-fb8611c1' # Ubuntu 12.04 LTS 64bit (EBS) + when 'eu-west-1' + 'ami-3d1f2b49' + when 'sa-east-1' + 'ami-d0429ccd' + when 'us-east-1' + 'ami-3202f25b' + when 'us-west-1' + 'ami-f5bfefb0' + when 'us-west-2' + 'ami-e0ec60d0' + end + end + super + end + + def addresses + requires :id + + service.addresses(:server => self) + end + + def console_output + requires :id + + service.get_console_output(id) + end + + def destroy + requires :id + + service.terminate_instances(id) + true + end + + remove_method :flavor_id + def flavor_id + @flavor && @flavor.id || attributes[:flavor_id] + end + + def flavor=(new_flavor) + @flavor = new_flavor + end + + def flavor + @flavor ||= service.flavors.all.find {|flavor| flavor.id == flavor_id} + end + + def key_pair + requires :key_name + service.key_pairs.all({'key-name' => key_name}).first + end + + def key_pair=(new_keypair) + self.key_name = new_keypair && new_keypair.name + end + + def ready? + state == 'running' + end + + def reboot + requires :id + service.reboot_instances(id) + true + end + + def run_instance_options + raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted? + requires :image_id + + options = { + 'BlockDeviceMapping' => block_device_mapping, + 'NetworkInterfaces' => network_interfaces, + 'ClientToken' => client_token, + 'DisableApiTermination' => disable_api_termination, + 'EbsOptimized' => ebs_optimized, + 'IamInstanceProfile.Arn' => @iam_instance_profile_arn, + 'IamInstanceProfile.Name' => @iam_instance_profile_name, + 'InstanceInitiatedShutdownBehavior' => instance_initiated_shutdown_behavior, + 'InstanceType' => flavor_id, + 'KernelId' => kernel_id, + 'KeyName' => key_name, + 'Monitoring.Enabled' => monitoring, + 'Placement.AvailabilityZone' => availability_zone, + 'Placement.GroupName' => placement_group, + 'Placement.Tenancy' => tenancy, + 'PrivateIpAddress' => private_ip_address, + 'RamdiskId' => ramdisk_id, + 'SecurityGroup' => groups, + 'SecurityGroupId' => security_group_ids, + 'SubnetId' => subnet_id, + 'UserData' => user_data, + } + options.delete_if {|key, value| value.nil?} + + # If subnet is defined then this is a Virtual Private Cloud. + # subnet & security group cannot co-exist. Attempting to specify + # both subnet and groups will cause an error. Instead please make + # use of Security Group Ids when working in a VPC. + if subnet_id + options.delete('SecurityGroup') + if associate_public_ip + options['NetworkInterface.0.DeviceIndex'] = 0 + options['NetworkInterface.0.AssociatePublicIpAddress'] = associate_public_ip + options['NetworkInterface.0.SubnetId'] = options['SubnetId'] + options.delete('SubnetId') + if options['SecurityGroupId'].kind_of?(Array) + options['SecurityGroupId'].each {|id| + options["NetworkInterface.0.SecurityGroupId.#{options['SecurityGroupId'].index(id)}"] = id + } + else + options["NetworkInterface.0.SecurityGroupId.0"] = options['SecurityGroupId'] + end + options.delete('SecurityGroupId') + if private_ip_address + options.delete('PrivateIpAddress') + options['NetworkInterface.0.PrivateIpAddress'] = private_ip_address + end + end + else + options.delete('SubnetId') + end + options + end + + def save + servers = service.servers.save_many(self, 1, 1) + merge_attributes(servers.first.attributes) + true + end + + def setup(credentials = {}) + requires :ssh_ip_address, :username + require 'net/ssh' + + commands = [ + %{mkdir .ssh}, + %{passwd -l #{username}}, + %{echo "#{Fog::JSON.encode(Fog::JSON.sanitize(attributes))}" >> ~/attributes.json} + ] + if public_key + commands << %{echo "#{public_key}" >> ~/.ssh/authorized_keys} + end + + # wait for aws to be ready + wait_for { sshable?(credentials) } + + Fog::SSH.new(ssh_ip_address, username, credentials).run(commands) + end + + def start + requires :id + service.start_instances(id) + true + end + + def stop(force = false) + requires :id + service.stop_instances(id, force) + true + end + + def volumes + requires :id + service.volumes(:server => self) + end + + #I tried to call it monitoring= and be smart with attributes[] + #but in #save a merge_attribute is called after run_instance + #thus making an un-necessary request. Use this until finding a clever solution + def monitor=(new_monitor) + if persisted? + case new_monitor + when true + response = service.monitor_instances(identity) + when false + response = service.unmonitor_instances(identity) + else + raise ArgumentError.new("only Boolean allowed here") + end + end + self.monitoring = new_monitor + end + + private + + def placement=(new_placement) + if new_placement.is_a?(Hash) + merge_attributes(new_placement) + else + self.attributes[:placement] = new_placement + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/servers.rb b/lib/fog/aws/models/compute/servers.rb new file mode 100644 index 000000000..55b80c492 --- /dev/null +++ b/lib/fog/aws/models/compute/servers.rb @@ -0,0 +1,211 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/server' + +module Fog + module Compute + class Aws + class Servers < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::Server + + # Creates a new server + # + # Aws.servers.new + # + # ==== Returns + # + # Returns the details of the new server + # + #>> Aws.servers.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + def all(filters = self.filters) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters.class} param is deprecated, use all('instance-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'instance-id' => [*filters]} + end + self.filters = filters + data = service.describe_instances(filters).body + load( + data['reservationSet'].map do |reservation| + reservation['instancesSet'].map do |instance| + instance.merge(:groups => reservation['groupSet'], :security_group_ids => reservation['groupIds']) + end + end.flatten + ) + end + + # Create between m and n servers with the server options specified in + # new_attributes. Equivalent to this loop, but happens in 1 request: + # + # 1.upto(n).map { create(new_attributes) } + # + # See the Aws RunInstances API. + def create_many(min_servers = 1, max_servers = nil, new_attributes = {}) + max_servers ||= min_servers + template = new(new_attributes) + save_many(template, min_servers, max_servers) + end + + # Bootstrap between m and n servers with the server options specified in + # new_attributes. Equivalent to this loop, but happens in 1 Aws request + # and the machines' spinup will happen in parallel: + # + # 1.upto(n).map { bootstrap(new_attributes) } + # + # See the Aws RunInstances API. + def bootstrap_many(min_servers = 1, max_servers = nil, new_attributes = {}) + template = service.servers.new(new_attributes) + _setup_bootstrap(template) + + servers = save_many(template, min_servers, max_servers) + servers.each do |server| + server.wait_for { ready? } + server.setup(:key_data => [server.private_key]) + end + servers + end + + def bootstrap(new_attributes = {}) + bootstrap_many(1, 1, new_attributes).first + end + + # Used to retrieve a server + # + # server_id is required to get the associated server information. + # + # You can run the following command to get the details: + # Aws.servers.get("i-5c973972") + # + # ==== Returns + # + #>> Aws.servers.get("i-5c973972") + # + # + + def get(server_id) + if server_id + self.class.new(:service => service).all('instance-id' => server_id).first + end + rescue Fog::Errors::NotFound + nil + end + + # From a template, create between m-n servers (see the Aws RunInstances API) + def save_many(template, min_servers = 1, max_servers = nil) + max_servers ||= min_servers + data = service.run_instances(template.image_id, min_servers, max_servers, template.run_instance_options) + # For some reason, Aws sometimes returns empty results alongside the real ones. Thus the select + data.body['instancesSet'].select { |instance_set| instance_set['instanceId'] }.map do |instance_set| + server = template.dup + server.merge_attributes(instance_set) + # expect eventual consistency + if (tags = server.tags) && tags.size > 0 + Fog.wait_for { server.reload rescue nil } + service.create_tags( + server.identity, + tags + ) + end + server + end + end + + private + + def _setup_bootstrap(server) + unless server.key_name + # first or create fog_#{credential} keypair + name = Fog.respond_to?(:credential) && Fog.credential || :default + unless server.key_pair = service.key_pairs.get("fog_#{name}") + server.key_pair = service.key_pairs.create( + :name => "fog_#{name}", + :public_key => server.public_key + ) + end + end + + security_group = service.security_groups.get(server.groups.first) + if security_group.nil? + raise Fog::Compute::AWS::Error, "The security group" \ + " #{server.groups.first} doesn't exist." + end + + # make sure port 22 is open in the first security group + authorized = security_group.ip_permissions.find do |ip_permission| + ip_permission['ipRanges'].first && ip_permission['ipRanges'].first['cidrIp'] == '0.0.0.0/0' && + ip_permission['fromPort'] == 22 && + ip_permission['ipProtocol'] == 'tcp' && + ip_permission['toPort'] == 22 + end + + unless authorized + security_group.authorize_port_range(22..22) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/snapshot.rb b/lib/fog/aws/models/compute/snapshot.rb new file mode 100644 index 000000000..cc0f1d798 --- /dev/null +++ b/lib/fog/aws/models/compute/snapshot.rb @@ -0,0 +1,53 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Snapshot < Fog::Model + identity :id, :aliases => 'snapshotId' + + attribute :description + attribute :encrypted + attribute :progress + attribute :created_at, :aliases => 'startTime' + attribute :owner_id, :aliases => 'ownerId' + attribute :state, :aliases => 'status' + attribute :tags, :aliases => 'tagSet' + attribute :volume_id, :aliases => 'volumeId' + attribute :volume_size, :aliases => 'volumeSize' + + def destroy + requires :id + + service.delete_snapshot(id) + true + end + + def ready? + state == 'completed' + end + + def save + raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted? + requires :volume_id + + data = service.create_snapshot(volume_id, description).body + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + true + end + + def volume + requires :id + service.describe_volumes(volume_id) + end + + private + + def volume=(new_volume) + self.volume_id = new_volume.volume_id + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/snapshots.rb b/lib/fog/aws/models/compute/snapshots.rb new file mode 100644 index 000000000..b8057097d --- /dev/null +++ b/lib/fog/aws/models/compute/snapshots.rb @@ -0,0 +1,48 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/snapshot' + +module Fog + module Compute + class Aws + class Snapshots < Fog::Collection + attribute :filters + attribute :volume + + model Fog::Compute::AWS::Snapshot + + def initialize(attributes) + self.filters ||= { 'RestorableBy' => 'self' } + super + end + + def all(filters_arg = filters, options = {}) + unless filters_arg.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters_arg.class} param is deprecated, use all('snapshot-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'snapshot-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_snapshots(filters.merge!(options)).body + load(data['snapshotSet']) + if volume + self.replace(self.select {|snapshot| snapshot.volume_id == volume.id}) + end + self + end + + def get(snapshot_id) + if snapshot_id + self.class.new(:service => service).all('snapshot-id' => snapshot_id).first + end + end + + def new(attributes = {}) + if volume + super({ 'volumeId' => volume.id }.merge!(attributes)) + else + super + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/spot_request.rb b/lib/fog/aws/models/compute/spot_request.rb new file mode 100644 index 000000000..e8c91a562 --- /dev/null +++ b/lib/fog/aws/models/compute/spot_request.rb @@ -0,0 +1,119 @@ +require 'fog/compute/models/server' + +module Fog + module Compute + class Aws + class SpotRequest < Fog::Compute::Server + identity :id, :aliases => 'spotInstanceRequestId' + + attribute :price, :aliases => 'spotPrice' + attribute :request_type, :aliases => 'type' + attribute :created_at, :aliases => 'createTime' + attribute :instance_count, :aliases => 'instanceCount' + attribute :instance_id, :aliases => 'instanceId' + attribute :state + + attribute :valid_from, :aliases => 'validFrom' + attribute :valid_until, :aliases => 'validUntil' + attribute :launch_group, :aliases => 'launchGroup' + attribute :availability_zone_group, :aliases => 'availabilityZoneGroup' + attribute :product_description, :aliases => 'productDescription' + + attribute :ebs_optimized, :aliases => 'LaunchSpecification.EbsOptimized' + attribute :groups, :aliases => 'LaunchSpecification.SecurityGroup' + attribute :key_name, :aliases => 'LaunchSpecification.KeyName' + attribute :availability_zone, :aliases => 'LaunchSpecification.Placement.AvailabilityZone' + attribute :flavor_id, :aliases => 'LaunchSpecification.InstanceType' + attribute :image_id, :aliases => 'LaunchSpecification.ImageId' + attribute :monitoring, :aliases => 'LaunchSpecification.Monitoring' + attribute :block_device_mapping, :aliases => 'LaunchSpecification.BlockDeviceMapping' + attribute :subnet_id, :aliases => 'LaunchSpecification.SubnetId' + attribute :iam_instance_profile, :aliases => 'LaunchSpecification.IamInstanceProfile' + + attribute :tags, :aliases => 'tagSet' + attribute :fault, :squash => 'message' + attribute :user_data + + attr_writer :iam_instance_profile_name, :iam_instance_profile_arn + + def initialize(attributes={}) + self.groups ||= ["default"] + self.flavor_id ||= 't1.micro' + self.image_id ||= begin + self.username ||= 'ubuntu' + + # Old 'connection' is renamed as service and should be used instead + prepare_service_value(attributes) + + case @service.instance_variable_get(:@region) # Ubuntu 10.04 LTS 64bit (EBS) + when 'ap-northeast-1' + 'ami-5e0fa45f' + when 'ap-southeast-1' + 'ami-f092eca2' + when 'eu-west-1' + 'ami-3d1f2b49' + when 'us-east-1' + 'ami-3202f25b' + when 'us-west-1' + 'ami-f5bfefb0' + end + end + super + end + + def destroy + requires :id + + service.cancel_spot_instance_requests(id) + true + end + + def key_pair + requires :key_name + + service.key_pairs.all(key_name).first + end + + def key_pair=(new_keypair) + self.key_name = new_keypair && new_keypair.name + end + + def ready? + state == 'active' + end + + def save + requires :image_id, :flavor_id, :price + + options = { + 'AvailabilityZoneGroup' => availability_zone_group, + 'InstanceCount' => instance_count, + 'LaunchGroup' => launch_group, + 'LaunchSpecification.BlockDeviceMapping' => block_device_mapping, + 'LaunchSpecification.KeyName' => key_name, + 'LaunchSpecification.Monitoring.Enabled' => monitoring, + 'LaunchSpecification.Placement.AvailabilityZone' => availability_zone, + 'LaunchSpecification.SecurityGroupId' => groups, + 'LaunchSpecification.EbsOptimized' => ebs_optimized, + 'LaunchSpecification.UserData' => user_data, + 'LaunchSpecification.SubnetId' => subnet_id, + 'LaunchSpecification.IamInstanceProfile.Arn' => @iam_instance_profile_arn, + 'LaunchSpecification.IamInstanceProfile.Name' => @iam_instance_profile_name, + 'Type' => request_type, + 'ValidFrom' => valid_from, + 'ValidUntil' => valid_until } + options.delete_if {|key, value| value.nil?} + + data = service.request_spot_instances(image_id, flavor_id, price, options).body + spot_instance_request = data['spotInstanceRequestSet'].first + spot_instance_request['launchSpecification'].each do |name,value| + spot_instance_request['LaunchSpecification.' + name[0,1].upcase + name[1..-1]] = value + end + spot_instance_request.merge(:groups => spot_instance_request['LaunchSpecification.GroupSet']) + spot_instance_request.merge(options) + merge_attributes( spot_instance_request ) + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/spot_requests.rb b/lib/fog/aws/models/compute/spot_requests.rb new file mode 100644 index 000000000..a3b167446 --- /dev/null +++ b/lib/fog/aws/models/compute/spot_requests.rb @@ -0,0 +1,86 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/spot_request' + +module Fog + module Compute + class Aws + class SpotRequests < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::SpotRequest + + def initialize(attributes) + self.filters ||= {} + super + end + + def all(filters = self.filters) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters.class} param is deprecated, use all('spot-instance-request-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'spot-instance-request-id' => [*filters]} + end + self.filters = filters + data = service.describe_spot_instance_requests(filters).body + load( + data['spotInstanceRequestSet'].map do |spot_instance_request| + spot_instance_request['LaunchSpecification.Placement.AvailabilityZone'] = spot_instance_request['launchedAvailabilityZone'] + spot_instance_request['launchSpecification'].each do |name,value| + spot_instance_request['LaunchSpecification.' + name[0,1].upcase + name[1..-1]] = value + end + spot_instance_request.merge(:groups => spot_instance_request['LaunchSpecification.GroupSet']) + spot_instance_request + end.flatten + ) + end + + def bootstrap(new_attributes = {}) + spot_request = service.spot_requests.new(new_attributes) + + unless new_attributes[:key_name] + # first or create fog_#{credential} keypair + name = Fog.respond_to?(:credential) && Fog.credential || :default + unless spot_request.key_pair = service.key_pairs.get("fog_#{name}") + spot_request.key_pair = service.key_pairs.create( + :name => "fog_#{name}", + :public_key => spot_request.public_key + ) + end + end + + # make sure port 22 is open in the first security group + security_group = service.security_groups.get(spot_request.groups.first) + authorized = security_group.ip_permissions.find do |ip_permission| + ip_permission['ipRanges'].first && ip_permission['ipRanges'].first['cidrIp'] == '0.0.0.0/0' && + ip_permission['fromPort'] == 22 && + ip_permission['ipProtocol'] == 'tcp' && + ip_permission['toPort'] == 22 + end + unless authorized + security_group.authorize_port_range(22..22) + end + + spot_request.save + Fog.wait_for { spot_request.reload.ready? rescue nil } + server = service.servers.get(spot_request.instance_id) + if spot_request.tags + service.create_tags( + spot_request.instance_id, + spot_request.tags + ) + end + server.wait_for { ready? } + server.setup(:key_data => [spot_request.private_key]) + server + end + + def get(spot_request_id) + if spot_request_id + self.class.new(:service => service).all('spot-instance-request-id' => spot_request_id).first + end + rescue Fog::Errors::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/subnet.rb b/lib/fog/aws/models/compute/subnet.rb new file mode 100644 index 000000000..76b9a9d7d --- /dev/null +++ b/lib/fog/aws/models/compute/subnet.rb @@ -0,0 +1,61 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Subnet < Fog::Model + identity :subnet_id, :aliases => 'subnetId' + attribute :state + attribute :vpc_id, :aliases => 'vpcId' + attribute :cidr_block, :aliases => 'cidrBlock' + attribute :available_ip_address_count, :aliases => 'availableIpAddressCount' + attribute :availability_zone, :aliases => 'availabilityZone' + attribute :tag_set, :aliases => 'tagSet' + attribute :map_public_ip_on_launch, :aliases => 'mapPublicIpOnLaunch' + + def ready? + requires :state + state == 'available' + end + + # Removes an existing subnet + # + # subnet.destroy + # + # ==== Returns + # + # True or false depending on the result + # + + def destroy + requires :subnet_id + + service.delete_subnet(subnet_id) + true + end + + # Create a subnet + # + # >> g = Aws.subnets.new(:vpc_id => "vpc-someId", :cidr_block => "10.0.0.0/24") + # >> g.save + # + # == Returns: + # + # requestId and a subnet object + # + + def save + requires :vpc_id, :cidr_block + options = {} + options['AvailabilityZone'] = availability_zone if availability_zone + data = service.create_subnet(vpc_id, cidr_block, options).body['subnet'] + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + true + + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/subnets.rb b/lib/fog/aws/models/compute/subnets.rb new file mode 100644 index 000000000..bbc757249 --- /dev/null +++ b/lib/fog/aws/models/compute/subnets.rb @@ -0,0 +1,95 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/subnet' + +module Fog + module Compute + class Aws + class Subnets < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::Subnet + + # Creates a new subnet + # + # Aws.subnets.new + # + # ==== Returns + # + # Returns the details of the new Subnet + # + #>> Aws.subnets.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all Subnets that have been created + # + # Aws.subnets.all + # + # ==== Returns + # + # Returns an array of all VPCs + # + #>> Aws.subnets.all + # + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.warning("all with #{filters_arg.class} param is deprecated, use all('subnet-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'subnet-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_subnets(filters).body + load(data['subnetSet']) + end + + # Used to retrieve a Subnet + # subnet-id is required to get the associated VPC information. + # + # You can run the following command to get the details: + # Aws.subnets.get("subnet-12345678") + # + # ==== Returns + # + #>> Aws.subnets.get("subnet-12345678") + # + # + + def get(subnet_id) + if subnet_id + self.class.new(:service => service).all('subnet-id' => subnet_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/tag.rb b/lib/fog/aws/models/compute/tag.rb new file mode 100644 index 000000000..8fc9354ee --- /dev/null +++ b/lib/fog/aws/models/compute/tag.rb @@ -0,0 +1,31 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Tag < Fog::Model + identity :key + + attribute :value + attribute :resource_id, :aliases => 'resourceId' + attribute :resource_type, :aliases => 'resourceType' + + def initialize(attributes = {}) + super + end + + def destroy + requires :key, :resource_id + service.delete_tags(resource_id, key => value) + true + end + + def save + requires :key, :resource_id + service.create_tags(resource_id, key => value) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/tags.rb b/lib/fog/aws/models/compute/tags.rb new file mode 100644 index 000000000..3fd394175 --- /dev/null +++ b/lib/fog/aws/models/compute/tags.rb @@ -0,0 +1,31 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/tag' + +module Fog + module Compute + class Aws + class Tags < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::Tag + + def initialize(attributes) + self.filters ||= {} + super + end + + def all(filters_arg = filters) + filters = filters_arg + data = service.describe_tags(filters).body + load(data['tagSet']) + end + + def get(key) + if key + self.class.new(:service => service).all('key' => key) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/volume.rb b/lib/fog/aws/models/compute/volume.rb new file mode 100644 index 000000000..ee1be170c --- /dev/null +++ b/lib/fog/aws/models/compute/volume.rb @@ -0,0 +1,126 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class Volume < Fog::Model + identity :id, :aliases => 'volumeId' + + attribute :attached_at, :aliases => 'attachTime' + attribute :availability_zone, :aliases => 'availabilityZone' + attribute :created_at, :aliases => 'createTime' + attribute :delete_on_termination, :aliases => 'deleteOnTermination' + attribute :device + attribute :iops + attribute :server_id, :aliases => 'instanceId' + attribute :size + attribute :encrypted + attribute :snapshot_id, :aliases => 'snapshotId' + attribute :state, :aliases => 'status' + attribute :tags, :aliases => 'tagSet' + attribute :type, :aliases => 'volumeType' + + def initialize(attributes = {}) + # assign server first to prevent race condition with persisted? + self.server = attributes.delete(:server) + super + end + + def destroy + requires :id + + service.delete_volume(id) + true + end + + def ready? + state == 'available' + end + + def save + raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted? + requires :availability_zone + requires_one :size, :snapshot_id + + if type == 'io1' + requires :iops + end + + data = service.create_volume(availability_zone, size, 'SnapshotId' => snapshot_id, 'VolumeType' => type, 'Iops' => iops, 'Encrypted' => encrypted).body + new_attributes = data.reject {|key,value| key == 'requestId'} + merge_attributes(new_attributes) + + if tags = self.tags + # expect eventual consistency + Fog.wait_for { self.reload rescue nil } + service.create_tags( + self.identity, + tags + ) + end + + if @server + self.server = @server + end + true + end + + def server + requires :server_id + service.servers.get(server_id) + end + + def server=(new_server) + if new_server + attach(new_server) + else + detach + end + end + + def snapshots + requires :id + service.snapshots(:volume => self) + end + + def snapshot(description) + requires :id + service.create_snapshot(id, description) + end + + def force_detach + detach(true) + end + + private + + def attachmentSet=(new_attachment_set) + merge_attributes(new_attachment_set.first || {}) + end + + def attach(new_server) + if !persisted? + @server = new_server + self.availability_zone = new_server.availability_zone + elsif new_server + requires :device + wait_for { ready? } + @server = nil + self.server_id = new_server.id + service.attach_volume(server_id, id, device) + reload + end + end + + def detach(force = false) + @server = nil + self.server_id = nil + if persisted? + service.detach_volume(id, 'Force' => force) + reload + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/volumes.rb b/lib/fog/aws/models/compute/volumes.rb new file mode 100644 index 000000000..71abf0a28 --- /dev/null +++ b/lib/fog/aws/models/compute/volumes.rb @@ -0,0 +1,117 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/volume' + +module Fog + module Compute + class Aws + class Volumes < Fog::Collection + attribute :filters + attribute :server + + model Fog::Compute::AWS::Volume + + # Used to create a volume. There are 3 arguments and availability_zone and size are required. You can generate a new key_pair as follows: + # Aws.volumes.create(:availability_zone => 'us-east-1a', :size => 10) + # + # ==== Returns + # + # + # + # The volume can be retrieved by running Aws.volumes.get("vol-1e2028b9"). See get method below. + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Used to return all volumes. + # Aws.volumes.all + # + # ==== Returns + # + #>>Aws.volumes.all + # + # + # The volume can be retrieved by running Aws.volumes.get("vol-1e2028b9"). See get method below. + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.deprecation("all with #{filters_arg.class} param is deprecated, use all('volume-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'volume-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_volumes(filters).body + load(data['volumeSet']) + if server + self.replace(self.select {|volume| volume.server_id == server.id}) + end + self + end + + # Used to retrieve a volume + # volume_id is required to get the associated volume information. + # + # You can run the following command to get the details: + # Aws.volumes.get("vol-1e2028b9") + # + # ==== Returns + # + #>> Aws.volumes.get("vol-1e2028b9") + # + # + + def get(volume_id) + if volume_id + self.class.new(:service => service).all('volume-id' => volume_id).first + end + end + + def new(attributes = {}) + if server + super({ :server => server }.merge!(attributes)) + else + super + end + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/vpc.rb b/lib/fog/aws/models/compute/vpc.rb new file mode 100644 index 000000000..50e4b1ae7 --- /dev/null +++ b/lib/fog/aws/models/compute/vpc.rb @@ -0,0 +1,75 @@ +require 'fog/core/model' + +module Fog + module Compute + class Aws + class VPC < Fog::Model + identity :id, :aliases => 'vpcId' + + attribute :state + attribute :cidr_block, :aliases => 'cidrBlock' + attribute :dhcp_options_id, :aliases => 'dhcpOptionsId' + attribute :tags, :aliases => 'tagSet' + attribute :tenancy, :aliases => 'instanceTenancy' + + def initialize(attributes={}) + self.dhcp_options_id ||= "default" + self.tenancy ||= "default" + super + end + + def ready? + requires :state + state == 'available' + end + + # Removes an existing vpc + # + # vpc.destroy + # + # ==== Returns + # + # True or false depending on the result + # + + def destroy + requires :id + + service.delete_vpc(id) + true + end + + # Create a vpc + # + # >> g = Aws.vpcs.new(:cidr_block => "10.1.2.0/24") + # >> g.save + # + # == Returns: + # + # True or an exception depending on the result. Keep in mind that this *creates* a new vpc. + # As such, it yields an InvalidGroup.Duplicate exception if you attempt to save an existing vpc. + # + + def save + requires :cidr_block + + data = service.create_vpc(cidr_block).body['vpcSet'].first + new_attributes = data.reject {|key,value| key == 'requestId'} + new_attributes = data.reject {|key,value| key == 'requestId' || key == 'tagSet' } + merge_attributes(new_attributes) + + if tags = self.tags + # expect eventual consistency + Fog.wait_for { self.reload rescue nil } + service.create_tags( + self.identity, + tags + ) + end + + true + end + end + end + end +end diff --git a/lib/fog/aws/models/compute/vpcs.rb b/lib/fog/aws/models/compute/vpcs.rb new file mode 100644 index 000000000..43fdea9e7 --- /dev/null +++ b/lib/fog/aws/models/compute/vpcs.rb @@ -0,0 +1,89 @@ +require 'fog/core/collection' +require 'fog/aws/models/compute/vpc' + +module Fog + module Compute + class Aws + class Vpcs < Fog::Collection + attribute :filters + + model Fog::Compute::AWS::VPC + + # Creates a new VPC + # + # Aws.vpcs.new + # + # ==== Returns + # + # Returns the details of the new VPC + # + #>> Aws.vpcs.new + # + # + + def initialize(attributes) + self.filters ||= {} + super + end + + # Returns an array of all VPCs that have been created + # + # Aws.vpcs.all + # + # ==== Returns + # + # Returns an array of all VPCs + # + #>> Aws.vpcs.all + # + # ] + # > + # + + def all(filters_arg = filters) + unless filters_arg.is_a?(Hash) + Fog::Logger.warning("all with #{filters_arg.class} param is deprecated, use all('vpc-id' => []) instead [light_black](#{caller.first})[/]") + filters_arg = {'vpc-id' => [*filters_arg]} + end + filters = filters_arg + data = service.describe_vpcs(filters).body + load(data['vpcSet']) + end + + # Used to retrieve a VPC + # vpc_id is required to get the associated VPC information. + # + # You can run the following command to get the details: + # Aws.vpcs.get("vpc-12345678") + # + # ==== Returns + # + #>> Aws.vpcs.get("vpc-12345678") + # + # + + def get(vpc_id) + if vpc_id + self.class.new(:service => service).all('vpc-id' => vpc_id).first + end + end + end + end + end +end diff --git a/lib/fog/aws/models/data_pipeline/pipeline.rb b/lib/fog/aws/models/data_pipeline/pipeline.rb new file mode 100644 index 000000000..54f516db0 --- /dev/null +++ b/lib/fog/aws/models/data_pipeline/pipeline.rb @@ -0,0 +1,63 @@ +require 'fog/core/model' + +module Fog + module AWS + class DataPipeline + class Pipeline < Fog::Model + identity :id, :aliases => 'pipelineId' + attribute :name + attribute :description + attribute :tags + attribute :user_id, :aliases => 'userId' + attribute :account_id, :aliases => 'accountId' + attribute :state, :aliases => 'pipelineState' + attribute :unique_id, :aliases => 'uniqueId' + + def initialize(attributes={}) + # Extract the 'fields' portion of a response to attributes + if attributes.include?('fields') + string_fields = attributes['fields'].select { |f| f.include?('stringValue') } + field_attributes = Hash[string_fields.map { |f| [f['key'][/^@(.+)$/, 1], f['stringValue']] }] + merge_attributes(field_attributes) + end + + super + end + + def save + requires :name + requires :unique_id + + data = service.create_pipeline(unique_id, name, nil, tags) + merge_attributes(data) + + true + end + + def activate + requires :id + + service.activate_pipeline(id) + + true + end + + def put(objects) + requires :id + + service.put_pipeline_definition(id, objects) + + true + end + + def destroy + requires :id + + service.delete_pipeline(id) + + true + end + end + end + end +end diff --git a/lib/fog/aws/models/data_pipeline/pipelines.rb b/lib/fog/aws/models/data_pipeline/pipelines.rb new file mode 100644 index 000000000..5ef0420db --- /dev/null +++ b/lib/fog/aws/models/data_pipeline/pipelines.rb @@ -0,0 +1,33 @@ +require 'fog/core/collection' +require 'fog/aws/models/data_pipeline/pipeline' + +module Fog + module AWS + class DataPipeline + class Pipelines < Fog::Collection + model Fog::AWS::DataPipeline::Pipeline + + def all + ids = [] + + begin + result = service.list_pipelines + ids << result['pipelineIdList'].map { |id| id['id'] } + end while (result['hasMoreResults'] && result['marker']) + + load(service.describe_pipelines(ids.flatten)['pipelineDescriptionList']) + end + + def get(id) + data = service.describe_pipelines([id])['pipelineDescriptionList'].first + new(data) + rescue Excon::Errors::BadRequest => error + data = Fog::JSON.decode(error.response.body) + raise unless data['__type'] == 'PipelineDeletedException' || data['__type'] == 'PipelineNotFoundException' + + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/dns/record.rb b/lib/fog/aws/models/dns/record.rb new file mode 100644 index 000000000..2fc1879a7 --- /dev/null +++ b/lib/fog/aws/models/dns/record.rb @@ -0,0 +1,116 @@ +require 'fog/core/model' + +module Fog + module DNS + class Aws + class Record < Fog::Model + extend Fog::Deprecation + deprecate :ip, :value + deprecate :ip=, :value= + + identity :name, :aliases => ['Name'] + + attribute :value, :aliases => ['ResourceRecords'] + attribute :ttl, :aliases => ['TTL'] + attribute :type, :aliases => ['Type'] + attribute :status, :aliases => ['Status'] + attribute :created_at, :aliases => ['SubmittedAt'] + attribute :alias_target, :aliases => ['AliasTarget'] + attribute :change_id, :aliases => ['Id'] + attribute :region, :aliases => ['Region'] + attribute :weight, :aliases => ['Weight'] + attribute :set_identifier, :aliases => ['SetIdentifier'] + attribute :failover, :aliases => ['Failover'] + attribute :geo_location, :aliases => ['GeoLocation'] + attribute :health_check_id, :aliases => ['HealthCheckId'] + + def initialize(attributes={}) + super + end + + def destroy + options = attributes_to_options('DELETE') + service.change_resource_record_sets(zone.id, [options]) + true + end + + def zone + @zone + end + + def save + unless self.alias_target + self.ttl ||= 3600 + end + options = attributes_to_options('CREATE') + data = service.change_resource_record_sets(zone.id, [options]).body + merge_attributes(data) + true + end + + def modify(new_attributes) + options = [] + + # Delete the current attributes + options << attributes_to_options('DELETE') + + # Create the new attributes + merge_attributes(new_attributes) + options << attributes_to_options('CREATE') + + data = service.change_resource_record_sets(zone.id, options).body + merge_attributes(data) + true + end + + # Returns true if record is insync. May only be called for newly created or modified records that + # have a change_id and status set. + def ready? + requires :change_id, :status + status == 'INSYNC' + end + + def reload + # If we have a change_id (newly created or modified), then reload performs a get_change to update status. + if change_id + data = service.get_change(change_id).body + merge_attributes(data) + self + else + super + end + end + + private + + def zone=(new_zone) + @zone = new_zone + end + + def attributes_to_options(action) + requires :name, :type, :zone + requires_one :value, :alias_target + options = { + :action => action, + :name => name, + :resource_records => [*value], + :alias_target => symbolize_keys(alias_target), + :ttl => ttl, + :type => type, + :weight => weight, + :set_identifier => set_identifier, + :region => region, + :failover => failover, + :geo_location => geo_location, + :health_check_id => health_check_id + } + unless self.alias_target + requires :ttl + options[:ttl] = ttl + end + options + end + end + end + end +end diff --git a/lib/fog/aws/models/dns/records.rb b/lib/fog/aws/models/dns/records.rb new file mode 100644 index 000000000..a2926bc7f --- /dev/null +++ b/lib/fog/aws/models/dns/records.rb @@ -0,0 +1,120 @@ +require 'fog/core/collection' +require 'fog/aws/models/dns/record' + +module Fog + module DNS + class Aws + class Records < Fog::Collection + attribute :is_truncated, :aliases => ['IsTruncated'] + attribute :max_items, :aliases => ['MaxItems'] + attribute :name + attribute :next_record_name, :aliases => ['NextRecordName'] + attribute :next_record_type, :aliases => ['NextRecordType'] + attribute :next_record_identifier, :aliases => ['NextRecordIdentifier'] + attribute :type + attribute :identifier + + attribute :zone + + model Fog::DNS::AWS::Record + + def all(options = {}) + requires :zone + options[:max_items] ||= max_items + options[:name] ||= zone.domain + options[:type] ||= type + options[:identifier] ||= identifier + options.delete_if {|key, value| value.nil?} + + data = service.list_resource_record_sets(zone.id, options).body + # NextRecordIdentifier is completely absent instead of nil, so set to nil, or iteration breaks. + data['NextRecordIdentifier'] = nil unless data.key?('NextRecordIdentifier') + + merge_attributes(data.reject {|key, value| !['IsTruncated', 'MaxItems', 'NextRecordName', 'NextRecordType', 'NextRecordIdentifier'].include?(key)}) + load(data['ResourceRecordSets']) + end + + # + # Load all zone records into the collection. + # + def all! + data = [] + + merge_attributes({'NextRecordName' => nil, + 'NextRecordType' => nil, + 'NextRecordIdentifier' => nil, + 'IsTruncated' => nil}) + + begin + options = { + :name => next_record_name, + :type => next_record_type, + :identifier => next_record_identifier + } + options.delete_if {|key, value| value.nil?} + + batch = service.list_resource_record_sets(zone.id, options).body + # NextRecordIdentifier is completely absent instead of nil, so set to nil, or iteration breaks. + batch['NextRecordIdentifier'] = nil unless batch.key?('NextRecordIdentifier') + + merge_attributes(batch.reject {|key, value| !['IsTruncated', 'MaxItems', 'NextRecordName', 'NextRecordType', 'NextRecordIdentifier'].include?(key)}) + + data.concat(batch['ResourceRecordSets']) + end while is_truncated + + load(data) + end + + # + # Aws Route 53 records are uniquely identified by a compound key of name, type, and identifier. + # #get allows one to retrieve a record using one or more of those key components. + # + # ==== Parameters + # * record_name - The name of the record to retrieve. + # * record_type - The type of record to retrieve, if nil, then the first matching record is returned. + # * record_identifier - The record set identifier to retrieve, if nil, then the first matching record is returned. + # + def get(record_name, record_type = nil, record_identifier = nil) + requires :zone + # Append a trailing period to the record_name if absent. + record_name = record_name + "." unless record_name.end_with?(".") + record_type = record_type.upcase unless record_type.nil? + + options = { + :max_items => 1, + :name => record_name, + :type => record_type, + :identifier => record_identifier + } + options.delete_if {|key, value| value.nil?} + + data = service.list_resource_record_sets(zone.id, options).body + # Get first record + data = data['ResourceRecordSets'].shift + + if data + record = new(data) + # make sure everything matches + if record.name == record_name + if (!record_type.nil? && record.type != record_type) || + (!record_identifier.nil? && record.set_identifier != record_identifier) + nil + else + record + end + end + else + nil + end + rescue Excon::Errors::NotFound + nil + end + + def new(attributes = {}) + requires :zone + super({ :zone => zone }.merge!(attributes)) + end + end + end + end +end diff --git a/lib/fog/aws/models/dns/zone.rb b/lib/fog/aws/models/dns/zone.rb new file mode 100644 index 000000000..9b90ca1b9 --- /dev/null +++ b/lib/fog/aws/models/dns/zone.rb @@ -0,0 +1,49 @@ +require 'fog/core/model' +# require 'fog/aws/models/dns/records' + +module Fog + module DNS + class Aws + class Zone < Fog::Model + identity :id, :aliases => 'Id' + + attribute :caller_reference, :aliases => 'CallerReference' + attribute :change_info, :aliases => 'ChangeInfo' + attribute :description, :aliases => 'Comment' + attribute :domain, :aliases => 'Name' + attribute :nameservers, :aliases => 'NameServers' + + def destroy + requires :identity + service.delete_hosted_zone(identity) + true + end + + def records + @records ||= begin + Fog::DNS::AWS::Records.new( + :zone => self, + :service => service + ) + end + end + + def save + requires :domain + options = {} + options[:caller_ref] = caller_reference if caller_reference + options[:comment] = description if description + data = service.create_hosted_zone(domain, options).body + merge_attributes(data) + true + end + + private + + define_method(:HostedZone=) do |new_hosted_zone| + merge_attributes(new_hosted_zone) + end + end + end + end +end diff --git a/lib/fog/aws/models/dns/zones.rb b/lib/fog/aws/models/dns/zones.rb new file mode 100644 index 000000000..eaff73d64 --- /dev/null +++ b/lib/fog/aws/models/dns/zones.rb @@ -0,0 +1,29 @@ +require 'fog/core/collection' +require 'fog/aws/models/dns/zone' + +module Fog + module DNS + class Aws + class Zones < Fog::Collection + attribute :marker, :aliases => 'Marker' + attribute :max_items, :aliases => 'MaxItems' + + model Fog::DNS::AWS::Zone + + def all(options = {}) + options['marker'] ||= marker + options['maxitems'] ||= max_items + data = service.list_hosted_zones(options).body['HostedZones'] + load(data) + end + + def get(zone_id) + data = service.get_hosted_zone(zone_id).body + new(data) + rescue Excon::Errors::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/cluster.rb b/lib/fog/aws/models/elasticache/cluster.rb new file mode 100644 index 000000000..37254e636 --- /dev/null +++ b/lib/fog/aws/models/elasticache/cluster.rb @@ -0,0 +1,69 @@ +require 'fog/core/model' + +module Fog + module AWS + class Elasticache + class Cluster < Fog::Model + # simple attributes + identity :id, :aliases => 'CacheClusterId' + attribute :auto_upgrade, :aliases => 'AutoMinorVersionUpgrade' + attribute :status, :aliases => 'CacheClusterStatus' + attribute :node_type, :aliases => 'CacheNodeType' + attribute :engine, :aliases => 'Engine' + attribute :engine_version, :aliases => 'EngineVersion' + attribute :num_nodes, :aliases => 'NumCacheNodes' + attribute :zone, :aliases => 'PreferredAvailabilityZone' + attribute :port, :aliases => 'Port' + attribute :maintenance_window, :aliases => 'PreferredMaintenanceWindow' + # complex attributes + attribute :nodes, :aliases => 'CacheNodes', :type => :array + attribute :parameter_group, :aliases => 'CacheParameterGroup' + attribute :pending_values, :aliases => 'PendingModifiedValues' + attribute :create_time, :aliases => 'CacheClusterCreateTime', :type => :timestamp + attribute :security_groups, :aliases => 'CacheSecurityGroups', :type => :array + attribute :notification_config, :aliases => 'NotificationConfiguration' + attribute :cache_subnet_group_name, :aliases => 'CacheSubnetGroupName' + attribute :vpc_security_groups, :aliases => 'VpcSecurityGroups', :type => :array + attribute :s3_snapshot_location, :aliases => 'SnapshotArns', :type => :array + + attr_accessor :parameter_group_name + + def ready? + status == 'available' + end + + def destroy + requires :id + service.delete_cache_cluster(id) + true + end + + def save + requires :id + + parameter_group ||= Hash.new + notification_config ||= Hash.new + + service.create_cache_cluster( + id, { + :node_type => node_type, + :security_group_names => security_groups, + :num_nodes => num_nodes, + :auto_minor_version_upgrade => auto_upgrade, + :engine => engine, + :engine_version => engine_version, + :notification_topic_arn => notification_config['TopicArn'], + :port => port, + :preferred_availablility_zone => zone, + :preferred_maintenance_window => maintenance_window, + :s3_snapshot_location => s3_snapshot_location, + :parameter_group_name => parameter_group_name || parameter_group['CacheParameterGroupName'], + :cache_subnet_group_name => cache_subnet_group_name, + :vpc_security_groups => vpc_security_groups, + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/clusters.rb b/lib/fog/aws/models/elasticache/clusters.rb new file mode 100644 index 000000000..41f8dcd7c --- /dev/null +++ b/lib/fog/aws/models/elasticache/clusters.rb @@ -0,0 +1,29 @@ +require 'fog/core/collection' +require 'fog/aws/models/elasticache/cluster' + +module Fog + module AWS + class Elasticache + class Clusters < Fog::Collection + model Fog::AWS::Elasticache::Cluster + + def all + load( + service.describe_cache_clusters( + nil, :show_node_info => true + ).body['CacheClusters'] + ) + end + + def get(identity, show_node_info = true) + new( + service.describe_cache_clusters( + identity, :show_node_info => show_node_info + ).body['CacheClusters'].first + ) + rescue Fog::AWS::Elasticache::NotFound + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/parameter_group.rb b/lib/fog/aws/models/elasticache/parameter_group.rb new file mode 100644 index 000000000..2d31c0130 --- /dev/null +++ b/lib/fog/aws/models/elasticache/parameter_group.rb @@ -0,0 +1,28 @@ +require 'fog/core/model' + +module Fog + module AWS + class Elasticache + class ParameterGroup < Fog::Model + identity :id, :aliases => 'CacheParameterGroupName' + attribute :description, :aliases => 'Description' + attribute :family, :aliases => 'CacheParameterGroupFamily' + + def destroy + requires :id + service.delete_cache_parameter_group(id) + true + end + + def save + requires :id + service.create_cache_parameter_group( + id, + description = id, + family = 'memcached1.4' + ) + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/parameter_groups.rb b/lib/fog/aws/models/elasticache/parameter_groups.rb new file mode 100644 index 000000000..caa8c1f98 --- /dev/null +++ b/lib/fog/aws/models/elasticache/parameter_groups.rb @@ -0,0 +1,28 @@ +require 'fog/core/collection' +require 'fog/aws/models/elasticache/parameter_group' + +module Fog + module AWS + class Elasticache + class ParameterGroups < Fog::Collection + model Fog::AWS::Elasticache::ParameterGroup + + def all + load( + service.describe_cache_parameter_groups.body['CacheParameterGroups'] + ) + end + + def get(identity) + new( + service.describe_cache_parameter_groups( + identity + ).body['CacheParameterGroups'].first + ) + rescue Fog::AWS::Elasticache::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/security_group.rb b/lib/fog/aws/models/elasticache/security_group.rb new file mode 100644 index 000000000..45623b8b4 --- /dev/null +++ b/lib/fog/aws/models/elasticache/security_group.rb @@ -0,0 +1,48 @@ +require 'fog/core/model' + +module Fog + module AWS + class Elasticache + class SecurityGroup < Fog::Model + identity :id, :aliases => 'CacheSecurityGroupName' + attribute :description, :aliases => 'Description' + attribute :ec2_groups, :aliases => 'EC2SecurityGroups', :type => :array + attribute :owner_id, :aliases => 'OwnerId' + + def ready? + ec2_groups.all?{|ingress| ingress['Status'] == 'authorized'} + end + + def destroy + requires :id + service.delete_cache_security_group(id) + true + end + + def save + requires :id + requires :description + service.create_cache_security_group(id, description) + end + + def authorize_ec2_group(group_name, group_owner_id=owner_id) + requires :id + requires :owner_id if group_owner_id.nil? + data = service.authorize_cache_security_group_ingress( + id, group_name, group_owner_id + ) + merge_attributes(data.body['CacheSecurityGroup']) + end + + def revoke_ec2_group(group_name, group_owner_id=owner_id) + requires :id + requires :owner_id if group_owner_id.nil? + data = service.revoke_cache_security_group_ingress( + id, group_name, group_owner_id + ) + merge_attributes(data.body['CacheSecurityGroup']) + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/security_groups.rb b/lib/fog/aws/models/elasticache/security_groups.rb new file mode 100644 index 000000000..e2d81f10b --- /dev/null +++ b/lib/fog/aws/models/elasticache/security_groups.rb @@ -0,0 +1,28 @@ +require 'fog/core/collection' +require 'fog/aws/models/elasticache/security_group' + +module Fog + module AWS + class Elasticache + class SecurityGroups < Fog::Collection + model Fog::AWS::Elasticache::SecurityGroup + + def all + load( + service.describe_cache_security_groups.body['CacheSecurityGroups'] + ) + end + + def get(identity) + new( + service.describe_cache_security_groups( + identity + ).body['CacheSecurityGroups'].first + ) + rescue Fog::AWS::Elasticache::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/subnet_group.rb b/lib/fog/aws/models/elasticache/subnet_group.rb new file mode 100644 index 000000000..589a31f40 --- /dev/null +++ b/lib/fog/aws/models/elasticache/subnet_group.rb @@ -0,0 +1,32 @@ +require 'fog/core/model' + +module Fog + module AWS + class Elasticache + class SubnetGroup < Fog::Model + identity :id, :aliases => ['CacheSubnetGroupName', :name] + attribute :description, :aliases => 'CacheSubnetGroupDescription' + attribute :vpc_id, :aliases => 'VpcId' + attribute :subnet_ids, :aliases => 'Subnets' + + def ready? + # Just returning true, as Elasticache subnet groups + # seem to not have a status, unlike RDS subnet groups. + true + end + + def save + requires :description, :id, :subnet_ids + service.create_cache_subnet_group(id, subnet_ids, description) + reload + end + + def destroy + requires :id + service.delete_cache_subnet_group(id) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/elasticache/subnet_groups.rb b/lib/fog/aws/models/elasticache/subnet_groups.rb new file mode 100644 index 000000000..e457a0f07 --- /dev/null +++ b/lib/fog/aws/models/elasticache/subnet_groups.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/elasticache/subnet_group' + +module Fog + module AWS + class Elasticache + class SubnetGroups < Fog::Collection + model Fog::AWS::Elasticache::SubnetGroup + + def all + data = service.describe_cache_subnet_groups.body['DescribeCacheSubnetGroupsResult']['CacheSubnetGroups'] + load(data) # data is an array of attribute hashes + end + + def get(identity) + data = service.describe_cache_subnet_groups(identity).body['DescribeCacheSubnetGroupsResult']['CacheSubnetGroups'].first + new(data) # data is an attribute hash + rescue Fog::AWS::Elasticache::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/backend_server_description.rb b/lib/fog/aws/models/elb/backend_server_description.rb new file mode 100644 index 000000000..f7daebf95 --- /dev/null +++ b/lib/fog/aws/models/elb/backend_server_description.rb @@ -0,0 +1,11 @@ +require 'fog/core/model' +module Fog + module AWS + class ELB + class BackendServerDescription < Fog::Model + attribute :policy_names, :aliases => 'PolicyNames' + attribute :instance_port, :aliases => 'InstancePort' + end + end + end +end diff --git a/lib/fog/aws/models/elb/backend_server_descriptions.rb b/lib/fog/aws/models/elb/backend_server_descriptions.rb new file mode 100644 index 000000000..1463ce24f --- /dev/null +++ b/lib/fog/aws/models/elb/backend_server_descriptions.rb @@ -0,0 +1,20 @@ +require 'fog/aws/models/elb/backend_server_description' +module Fog + module AWS + class ELB + class BackendServerDescriptions < Fog::Collection + model Fog::AWS::ELB::BackendServerDescription + + attr_accessor :data, :load_balancer + + def all + load(data) + end + + def get(instance_port) + all.find{|e| e.instance_port == instance_port} + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/listener.rb b/lib/fog/aws/models/elb/listener.rb new file mode 100644 index 000000000..d99950989 --- /dev/null +++ b/lib/fog/aws/models/elb/listener.rb @@ -0,0 +1,56 @@ +require 'fog/core/model' +module Fog + module AWS + class ELB + class Listener < Fog::Model + attribute :policy_names, :aliases => 'PolicyNames' + attribute :instance_port, :aliases => 'InstancePort' + attribute :instance_protocol, :aliases => 'InstanceProtocol' + attribute :lb_port, :aliases => 'LoadBalancerPort' + attribute :protocol, :aliases => 'Protocol' + attribute :ssl_id, :aliases => 'SSLCertificateId' + + def initialize(attributes={}) + # set defaults, which may be overridden in super + merge_attributes(:policy_names => [], :instance_port => 80, :instance_protocol => 'HTTP', :lb_port => 80, :protocol => 'HTTP') + super + end + + def save + requires :load_balancer, :instance_port, :lb_port, :protocol, :instance_protocol + service.create_load_balancer_listeners(load_balancer.id, [to_params]) + reload + end + + def destroy + requires :load_balancer, :lb_port + service.delete_load_balancer_listeners(load_balancer.id, [lb_port]) + reload + end + + # Return the policy associated with this load balancer + def policy + load_balancer.policies.get(policy_names.first) + end + + def reload + load_balancer.reload + end + + def load_balancer + collection.load_balancer + end + + def to_params + { + 'InstancePort' => instance_port, + 'InstanceProtocol' => instance_protocol, + 'LoadBalancerPort' => lb_port, + 'Protocol' => protocol, + 'SSLCertificateId' => ssl_id + } + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/listeners.rb b/lib/fog/aws/models/elb/listeners.rb new file mode 100644 index 000000000..98b0201e6 --- /dev/null +++ b/lib/fog/aws/models/elb/listeners.rb @@ -0,0 +1,30 @@ +require 'fog/aws/models/elb/listener' +module Fog + module AWS + class ELB + class Listeners < Fog::Collection + model Fog::AWS::ELB::Listener + + attr_accessor :data, :load_balancer + + def all + load(munged_data) + end + + def get(lb_port) + all.find{|listener| listener.lb_port == lb_port} + end + + private + # Munge an array of ListenerDescription hashes like: + # {'Listener' => listener, 'PolicyNames' => []} + # to an array of listeners with a PolicyNames key + def munged_data + data.map {|description| + description['Listener'].merge('PolicyNames' => description['PolicyNames']) + } + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/load_balancer.rb b/lib/fog/aws/models/elb/load_balancer.rb new file mode 100644 index 000000000..81885d2f2 --- /dev/null +++ b/lib/fog/aws/models/elb/load_balancer.rb @@ -0,0 +1,241 @@ +require 'fog/core/model' +module Fog + module AWS + class ELB + class LoadBalancer < Fog::Model + identity :id, :aliases => 'LoadBalancerName' + attribute :availability_zones, :aliases => 'AvailabilityZones' + attribute :created_at, :aliases => 'CreatedTime' + attribute :dns_name, :aliases => 'DNSName' + attribute :health_check, :aliases => 'HealthCheck' + attribute :instances, :aliases => 'Instances' + attribute :source_group, :aliases => 'SourceSecurityGroup' + attribute :hosted_zone_name, :aliases => 'CanonicalHostedZoneName' + attribute :hosted_zone_name_id, :aliases => 'CanonicalHostedZoneNameID' + attribute :subnet_ids, :aliases => 'Subnets' + attribute :security_groups, :aliases => 'SecurityGroups' + attribute :scheme, :aliases => 'Scheme' + attribute :vpc_id, :aliases => 'VPCId' + attribute :tags, :aliases => 'tagSet' + + def initialize(attributes={}) + if attributes[:subnet_ids] ||= attributes['Subnets'] + attributes[:availability_zones] ||= attributes['AvailabilityZones'] + else + attributes[:availability_zones] ||= attributes['AvailabilityZones'] || %w(us-east-1a us-east-1b us-east-1c us-east-1d) + end + unless attributes['ListenerDescriptions'] + new_listener = Fog::AWS::ELB::Listener.new + attributes['ListenerDescriptions'] = [{ + 'Listener' => new_listener.to_params, + 'PolicyNames' => new_listener.policy_names + }] + end + super + end + + def connection_draining? + requires :id + service.describe_load_balancer_attributes(id).body['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['ConnectionDraining']['Enabled'] + end + + def connection_draining_timeout + requires :id + service.describe_load_balancer_attributes(id).body['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['ConnectionDraining']['Timeout'] + end + + def set_connection_draining(enabled, timeout=nil) + requires :id + attrs = {'Enabled' => enabled} + attrs['Timeout'] = timeout if timeout + service.modify_load_balancer_attributes(id, 'ConnectionDraining' => attrs) + end + + def cross_zone_load_balancing? + requires :id + service.describe_load_balancer_attributes(id).body['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['CrossZoneLoadBalancing']['Enabled'] + end + + def cross_zone_load_balancing= value + requires :id + service.modify_load_balancer_attributes(id, 'CrossZoneLoadBalancing' => {'Enabled' => value}) + end + + def connection_settings_idle_timeout + requires :id + service.describe_load_balancer_attributes(id).body['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['ConnectionSettings']['IdleTimeout'] + end + + def set_connection_settings_idle_timeout(timeout=60) + requires :id + attrs = {'IdleTimeout' => timeout} + service.modify_load_balancer_attributes(id,'ConnectionSettings' => attrs) + end + + def register_instances(instances) + requires :id + data = service.register_instances_with_load_balancer(instances, id).body['RegisterInstancesWithLoadBalancerResult'] + data['Instances'].map!{|h| h['InstanceId']} + merge_attributes(data) + end + + def deregister_instances(instances) + requires :id + data = service.deregister_instances_from_load_balancer(instances, id).body['DeregisterInstancesFromLoadBalancerResult'] + data['Instances'].map!{|h| h['InstanceId']} + merge_attributes(data) + end + + def enable_availability_zones(zones) + requires :id + data = service.enable_availability_zones_for_load_balancer(zones, id).body['EnableAvailabilityZonesForLoadBalancerResult'] + merge_attributes(data) + end + + def disable_availability_zones(zones) + requires :id + data = service.disable_availability_zones_for_load_balancer(zones, id).body['DisableAvailabilityZonesForLoadBalancerResult'] + merge_attributes(data) + end + + def attach_subnets(subnet_ids) + requires :id + data = service.attach_load_balancer_to_subnets(subnet_ids, id).body['AttachLoadBalancerToSubnetsResult'] + merge_attributes(data) + end + + def detach_subnets(subnet_ids) + requires :id + data = service.detach_load_balancer_from_subnets(subnet_ids, id).body['DetachLoadBalancerFromSubnetsResult'] + merge_attributes(data) + end + + def apply_security_groups(security_groups) + requires :id + data = service.apply_security_groups_to_load_balancer(security_groups, id).body['ApplySecurityGroupsToLoadBalancerResult'] + merge_attributes(data) + end + + def instance_health + requires :id + @instance_health ||= service.describe_instance_health(id).body['DescribeInstanceHealthResult']['InstanceStates'] + end + + def instances_in_service + instance_health.select{|hash| hash['State'] == 'InService'}.map{|hash| hash['InstanceId']} + end + + def instances_out_of_service + instance_health.select{|hash| hash['State'] == 'OutOfService'}.map{|hash| hash['InstanceId']} + end + + def configure_health_check(health_check) + requires :id + data = service.configure_health_check(id, health_check).body['ConfigureHealthCheckResult']['HealthCheck'] + merge_attributes(:health_check => data) + end + + def backend_server_descriptions + Fog::AWS::ELB::BackendServerDescriptions.new({ + :data => attributes['BackendServerDescriptions'], + :service => service, + :load_balancer => self + }) + end + + def listeners + Fog::AWS::ELB::Listeners.new({ + :data => attributes['ListenerDescriptions'], + :service => service, + :load_balancer => self + }) + end + + def policies + Fog::AWS::ELB::Policies.new({ + :data => policy_descriptions, + :service => service, + :load_balancer => self + }) + end + + def policy_descriptions + requires :id + @policy_descriptions ||= service.describe_load_balancer_policies(id).body["DescribeLoadBalancerPoliciesResult"]["PolicyDescriptions"] + end + + def set_listener_policy(port, policy_name) + requires :id + policy_name = [policy_name].flatten + service.set_load_balancer_policies_of_listener(id, port, policy_name) + reload + end + + def set_listener_ssl_certificate(port, ssl_certificate_id) + requires :id + service.set_load_balancer_listener_ssl_certificate(id, port, ssl_certificate_id) + reload + end + + def unset_listener_policy(port) + set_listener_policy(port, []) + end + + def ready? + # ELB requests are synchronous + true + end + + def tags + requires :id + service.describe_tags(id). + body['DescribeTagsResult']["LoadBalancers"][0]["Tags"] + + end + def add_tags(new_tags) + requires :id + service.add_tags(id, new_tags) + tags + end + + def remove_tags(tag_keys) + requires :id + service.remove_tags(id, tag_keys) + tags + end + + + def save + requires :id + requires :listeners + # with the VPC release, the ELB can have either availability zones or subnets + # if both are specified, the availability zones have preference + #requires :availability_zones + if (availability_zones || subnet_ids) + service.create_load_balancer(availability_zones, id, listeners.map{|l| l.to_params}) if availability_zones + service.create_load_balancer(nil, id, listeners.map{|l| l.to_params}, {:subnet_ids => subnet_ids, :security_groups => security_groups, :scheme => scheme}) if subnet_ids && !availability_zones + else + throw Fog::Errors::Error.new("No availability zones or subnet ids specified") + end + + # reload instead of merge attributes b/c some attrs (like HealthCheck) + # may be set, but only the DNS name is returned in the create_load_balance + # API call + reload + end + + def reload + super + @instance_health = nil + @policy_descriptions = nil + self + end + + def destroy + requires :id + service.delete_load_balancer(id) + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/load_balancers.rb b/lib/fog/aws/models/elb/load_balancers.rb new file mode 100644 index 000000000..889e44a52 --- /dev/null +++ b/lib/fog/aws/models/elb/load_balancers.rb @@ -0,0 +1,37 @@ +require 'fog/aws/models/elb/load_balancer' +module Fog + module AWS + class ELB + class LoadBalancers < Fog::Collection + model Fog::AWS::ELB::LoadBalancer + + # Creates a new load balancer + def initialize(attributes={}) + super + end + + def all + result = [] + marker = nil + finished = false + while !finished + data = service.describe_load_balancers('Marker' => marker).body + result.concat(data['DescribeLoadBalancersResult']['LoadBalancerDescriptions']) + marker = data['DescribeLoadBalancersResult']['NextMarker'] + finished = marker.nil? + end + load(result) # data is an array of attribute hashes + end + + def get(identity) + if identity + data = service.describe_load_balancers('LoadBalancerNames' => identity).body['DescribeLoadBalancersResult']['LoadBalancerDescriptions'].first + new(data) + end + rescue Fog::AWS::ELB::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/policies.rb b/lib/fog/aws/models/elb/policies.rb new file mode 100644 index 000000000..fa613c1db --- /dev/null +++ b/lib/fog/aws/models/elb/policies.rb @@ -0,0 +1,52 @@ +require 'fog/aws/models/elb/policy' +module Fog + module AWS + class ELB + class Policies < Fog::Collection + model Fog::AWS::ELB::Policy + + attr_accessor :data, :load_balancer + + def all + load(munged_data) + end + + def get(id) + all.find{|policy| id == policy.id} + end + + private + def munged_data + data.reduce([]){|m,e| + policy_attribute_descriptions = e["PolicyAttributeDescriptions"] + + policy = { + :id => e["PolicyName"], + :type_name => e["PolicyTypeName"], + :policy_attributes => policy_attributes(policy_attribute_descriptions) + } + + case e["PolicyTypeName"] + when 'AppCookieStickinessPolicyType' + cookie_name = policy_attribute_descriptions.find{|h| h['AttributeName'] == 'CookieName'}['AttributeValue'] + policy['CookieName'] = cookie_name if cookie_name + when 'LBCookieStickinessPolicyType' + cookie_expiration_period = policy_attribute_descriptions.find{|h| h['AttributeName'] == 'CookieExpirationPeriod'}['AttributeValue'].to_i + policy['CookieExpirationPeriod'] = cookie_expiration_period if cookie_expiration_period > 0 + end + + m << policy + m + } + end + + def policy_attributes(policy_attribute_descriptions) + policy_attribute_descriptions.reduce({}){|m,e| + m[e["AttributeName"]] = e["AttributeValue"] + m + } + end + end + end + end +end diff --git a/lib/fog/aws/models/elb/policy.rb b/lib/fog/aws/models/elb/policy.rb new file mode 100644 index 000000000..5a289dc1d --- /dev/null +++ b/lib/fog/aws/models/elb/policy.rb @@ -0,0 +1,59 @@ +require 'fog/core/model' +module Fog + module AWS + class ELB + class Policy < Fog::Model + identity :id, :aliases => 'PolicyName' + + attribute :cookie, :aliases => 'CookieName' + attribute :expiration, :aliases => 'CookieExpirationPeriod' + attribute :type_name + attribute :policy_attributes + + attr_accessor :cookie_stickiness # Either :app or :lb + + def save + requires :id, :load_balancer + service_method = nil + args = [load_balancer.id, id] + + if cookie_stickiness + case cookie_stickiness + when :app + requires :cookie + method = :create_app_cookie_stickiness_policy + args << cookie + when :lb + method = :create_lb_cookie_stickiness_policy + args << expiration if expiration + else + raise ArgumentError.new('cookie_stickiness must be :app or :lb') + end + else + requires :type_name, :policy_attributes + method = :create_load_balancer_policy + args << type_name + args << policy_attributes + end + + service.send(method, *args) + reload + end + + def destroy + requires :id, :load_balancer + service.delete_load_balancer_policy(load_balancer.id, id) + reload + end + + def reload + load_balancer.reload + end + + def load_balancer + collection.load_balancer + end + end + end + end +end diff --git a/lib/fog/aws/models/glacier/archive.rb b/lib/fog/aws/models/glacier/archive.rb new file mode 100644 index 000000000..c8c0b7ab3 --- /dev/null +++ b/lib/fog/aws/models/glacier/archive.rb @@ -0,0 +1,68 @@ +require 'fog/core/model' + +module Fog + module AWS + class Glacier + class Archive < Fog::Model + identity :id + attribute :description + attribute :body + + attr_accessor :multipart_chunk_size #must be a power of 2 multiple of 1MB + + def vault + @vault + end + + def save + requires :body, :vault + + if multipart_chunk_size && body.respond_to?(:read) + self.id = multipart_save + else + data = service.create_archive(vault.id, body, 'description' => description) + self.id = data.headers['x-amz-archive-id'] + end + true + end + + def destroy + requires :id + service.delete_archive(vault.id,id) + end + + private + + def vault=(new_vault) + @vault = new_vault + end + + def multipart_save + # Initiate the upload + res = service.initiate_multipart_upload vault.id, multipart_chunk_size, 'description' => description + upload_id = res.headers["x-amz-multipart-upload-id"] + + hash = Fog::AWS::Glacier::TreeHash.new + + if body.respond_to?(:rewind) + body.rewind rescue nil + end + offset = 0 + while (chunk = body.read(multipart_chunk_size)) do + part_hash = hash.add_part(chunk) + part_upload = service.upload_part(vault.id, upload_id, chunk, offset, part_hash ) + offset += chunk.bytesize + end + + rescue + # Abort the upload & reraise + service.abort_multipart_upload(vault.id, upload_id) if upload_id + raise + else + # Complete the upload + service.complete_multipart_upload(vault.id, upload_id, offset, hash.hexdigest).headers['x-amz-archive-id'] + end + end + end + end +end diff --git a/lib/fog/aws/models/glacier/archives.rb b/lib/fog/aws/models/glacier/archives.rb new file mode 100644 index 000000000..59c058ee9 --- /dev/null +++ b/lib/fog/aws/models/glacier/archives.rb @@ -0,0 +1,26 @@ +require 'fog/core/collection' +require 'fog/aws/models/glacier/archive' + +module Fog + module AWS + class Glacier + class Archives < Fog::Collection + model Fog::AWS::Glacier::Archive + attribute :vault + #you can't list a vault's archives + def all + nil + end + + def get(key) + new(:id => key) + end + + def new(attributes = {}) + requires :vault + super({ :vault => vault }.merge!(attributes)) + end + end + end + end +end diff --git a/lib/fog/aws/models/glacier/job.rb b/lib/fog/aws/models/glacier/job.rb new file mode 100644 index 000000000..54caa5118 --- /dev/null +++ b/lib/fog/aws/models/glacier/job.rb @@ -0,0 +1,61 @@ +require 'fog/core/model' + +module Fog + module AWS + class Glacier + class Job < Fog::Model + ARCHIVE = 'archive-retrieval' + INVENTORY = 'inventory-retrieval' + + identity :id, :aliases => "JobId" + attribute :action, :aliases => "Action" + attribute :archive_id, :aliases => "ArchiveId" + attribute :archive_size, :aliases => "ArchiveSizeInBytes", :type => :integer + attribute :completed, :aliases => "Completed", :type => :boolean + attribute :completed_at, :aliases => "CompletionDate", :type => :time + attribute :created_at, :aliases => "CreationDate", :type => :time + attribute :inventory_size, :aliases => "InventorySizeInBytes", :type => :integer + attribute :description, :aliases=> "JobDescription" + attribute :tree_hash, :aliases=> "SHA256TreeHash" + attribute :sns_topic, :aliases => "SNSTopic" + attribute :status_code, :aliases=> "StatusCode" + attribute :status_message, :aliases=> "StatusMessage" + attribute :vault_arn, :aliases=> "VaultARN" + attribute :format + attribute :type + + def ready? + completed + end + + def save + requires :vault, :type + specification = {'Type' => type, 'ArchiveId' => archive_id, 'Format' => format, 'Description' => description, 'SNSTopic' => sns_topic}.reject{|k,v| v.nil?} + + data = service.initiate_job(vault.id, specification) + self.id = data.headers['x-amz-job-id'] + reload + end + + def vault + @vault + end + + #pass :range => 1..1234 to only retrieve those bytes + #pass :io => f to stream the response to that tio + def get_output(options={}) + if io = options.delete(:io) + options = options.merge :response_block => lambda {|chunk, remaining_bytes, total_bytes| io.write chunk} + end + options['Range'] = options.delete :range + service.get_job_output(vault.id, id, options) + end + + private + def vault=(new_vault) + @vault = new_vault + end + end + end + end +end diff --git a/lib/fog/aws/models/glacier/jobs.rb b/lib/fog/aws/models/glacier/jobs.rb new file mode 100644 index 000000000..724b8a3d3 --- /dev/null +++ b/lib/fog/aws/models/glacier/jobs.rb @@ -0,0 +1,40 @@ +require 'fog/core/collection' +require 'fog/aws/models/glacier/job' + +module Fog + module AWS + class Glacier + class Jobs < Fog::Collection + model Fog::AWS::Glacier::Job + attribute :vault + attribute :filters + + def initialize(attributes) + self.filters = {} + super + end + + # acceptable filters are: + # statuscode InProgress/Failed/Succeeded + # completed (true/false) + def all(filters = self.filters) + self.filters = filters + data = service.list_jobs(vault.id, self.filters).body['JobList'] + load(data) + end + + def get(key) + data = service.describe_job(vault.id, key).body + new(data) + rescue Excon::Errors::NotFound + nil + end + + def new(attributes = {}) + requires :vault + super({ :vault => vault }.merge!(attributes)) + end + end + end + end +end diff --git a/lib/fog/aws/models/glacier/vault.rb b/lib/fog/aws/models/glacier/vault.rb new file mode 100644 index 000000000..120966885 --- /dev/null +++ b/lib/fog/aws/models/glacier/vault.rb @@ -0,0 +1,50 @@ +require 'fog/core/model' +require 'fog/aws/models/glacier/archives' +require 'fog/aws/models/glacier/jobs' + +module Fog + module AWS + class Glacier + class Vault < Fog::Model + identity :id, :aliases => 'VaultName' + attribute :created_at, :aliases => 'CreationDate', :type => :time + attribute :last_inventory_at, :aliases => 'LastInventoryDate', :type => :time + attribute :number_of_archives, :aliases => 'NumberOfArchives', :type => :integer + attribute :size_in_bytes, :aliases => 'SizeInBytes', :type => :integer + attribute :arn, :aliases => 'VaultARN' + + def ready? + # Glacier requests are synchronous + true + end + + def archives + @archives ||= Fog::AWS::Glacier::Archives.new(:vault => self, :service => service) + end + + def jobs(filters={}) + Fog::AWS::Glacier::Jobs.new(:vault => self, :service => service, :filters => filters) + end + + def set_notification_configuration(topic, events) + service.set_vault_notification_configuration(id, topic, events) + end + + def delete_notification_configuration + service.delete_vault_notification_configuration(id) + end + + def save + requires :id + service.create_vault(id) + reload + end + + def destroy + requires :id + service.delete_vault(id) + end + end + end + end +end diff --git a/lib/fog/aws/models/glacier/vaults.rb b/lib/fog/aws/models/glacier/vaults.rb new file mode 100644 index 000000000..de7629b9a --- /dev/null +++ b/lib/fog/aws/models/glacier/vaults.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/glacier/vault' + +module Fog + module AWS + class Glacier + class Vaults < Fog::Collection + model Fog::AWS::Glacier::Vault + + def all + data = service.list_vaults.body['VaultList'] + load(data) + end + + def get(key) + data = service.describe_vault(key).body + new(data) + rescue Excon::Errors::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/access_key.rb b/lib/fog/aws/models/iam/access_key.rb new file mode 100644 index 000000000..d3928eff2 --- /dev/null +++ b/lib/fog/aws/models/iam/access_key.rb @@ -0,0 +1,39 @@ +require 'fog/core/model' + +module Fog + module AWS + class IAM + class AccessKey < Fog::Model + identity :id, :aliases => 'AccessKeyId' + attribute :username, :aliases => 'UserName' + attribute :secret_access_key, :aliases => 'SecretAccessKey' + attribute :status, :aliases => 'Status' + + def save + requires :username + + if !persisted? + data = service.create_access_key('UserName'=> username).body["AccessKey"] + else + data = service.update_access_key(id, status, "UserName" => username).body["AccessKey"] + end + merge_attributes(data) + true + end + + def destroy + requires :id + requires :username + + service.delete_access_key(id,'UserName'=> username) + true + end + + def user + requires :username + service.users.get(username) + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/access_keys.rb b/lib/fog/aws/models/iam/access_keys.rb new file mode 100644 index 000000000..147000afe --- /dev/null +++ b/lib/fog/aws/models/iam/access_keys.rb @@ -0,0 +1,32 @@ +require 'fog/core/collection' +require 'fog/aws/models/iam/access_key' + +module Fog + module AWS + class IAM + class AccessKeys < Fog::Collection + model Fog::AWS::IAM::AccessKey + + def initialize(attributes = {}) + @username = attributes[:username] + super + end + + def all + data = service.list_access_keys('UserName'=> @username).body['AccessKeys'] + # Aws response doesn't contain the UserName, this injects it + data.each {|access_key| access_key['UserName'] = @username } + load(data) + end + + def get(identity) + self.all.select {|access_key| access_key.id == identity}.first + end + + def new(attributes = {}) + super({ :username => @username }.merge!(attributes)) + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/policies.rb b/lib/fog/aws/models/iam/policies.rb new file mode 100644 index 000000000..7bdbadfed --- /dev/null +++ b/lib/fog/aws/models/iam/policies.rb @@ -0,0 +1,40 @@ +require 'fog/core/collection' +require 'fog/aws/models/iam/policy' + +module Fog + module AWS + class IAM + class Policies < Fog::Collection + model Fog::AWS::IAM::Policy + + def initialize(attributes = {}) + @username = attributes[:username] + raise ArgumentError.new("Can't get a policy's user without a username") unless @username + super + end + + def all + # Aws method get_user_policy only returns an array of policy names, this is kind of useless, + # that's why it has to loop through the list to get the details of each element. I don't like it because it makes this method slow + policy_names = service.list_user_policies(@username).body['PolicyNames'] # it returns an array + policies = [] + policy_names.each do |policy_name| + policies << service.get_user_policy(policy_name,@username).body['Policy'] + end + load(policies) # data is an array of attribute hashes + end + + def get(identity) + data = service.get_user_policy(identity,@username).body['Policy'] + new(data) # data is an attribute hash + rescue Fog::AWS::IAM::NotFound + nil + end + + def new(attributes = {}) + super({ :username => @username }.merge!(attributes)) + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/policy.rb b/lib/fog/aws/models/iam/policy.rb new file mode 100644 index 000000000..652b691bf --- /dev/null +++ b/lib/fog/aws/models/iam/policy.rb @@ -0,0 +1,36 @@ +require 'fog/core/model' + +module Fog + module AWS + class IAM + class Policy < Fog::Model + identity :id, :aliases => 'PolicyName' + attribute :username, :aliases => 'UserName' + attribute :document, :aliases => 'PolicyDocument' + + def save + requires :id + requires :username + requires :document + + data = service.put_user_policy(username, id, document).body + merge_attributes(data) + true + end + + def destroy + requires :id + requires :username + + service.delete_user_policy(username, id) + true + end + + def user + requires :username + service.users.get(username) + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/role.rb b/lib/fog/aws/models/iam/role.rb new file mode 100644 index 000000000..9efb2c135 --- /dev/null +++ b/lib/fog/aws/models/iam/role.rb @@ -0,0 +1,34 @@ +require 'fog/core/model' + +module Fog + module AWS + class IAM + class Role < Fog::Model + + identity :id, :aliases => 'RoleId' + attribute :rolename, :aliases => 'RoleName' + attribute :create_date, :aliases => 'CreateDate', :type => :time + attribute :assume_role_policy_document, :aliases => 'AssumeRolePolicyDocument' + attribute :arn, :aliases => 'Arn' + attribute :path, :aliases => 'Path' + + def save + raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted? + requires :rolename + requires :assume_role_policy_document + + data = service.create_role(rolename, assume_role_policy_document, path).body["Role"] + merge_attributes(data) + true + end + + def destroy + requires :rolename + + service.delete_role(rolename) + true + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/roles.rb b/lib/fog/aws/models/iam/roles.rb new file mode 100644 index 000000000..c3f567746 --- /dev/null +++ b/lib/fog/aws/models/iam/roles.rb @@ -0,0 +1,37 @@ +require 'fog/core/collection' +require 'fog/aws/models/iam/role' + +module Fog + module AWS + class IAM + class Roles < Fog::Collection + model Fog::AWS::IAM::Role + + def initialize(attributes = {}) + super + end + + def all + data = service.list_roles.body['Roles'] + load(data) + end + + def get(identity) + role = nil + begin + role = service.roles.new( service.get_role( identity ).data[:body]["Role"] ) + rescue Excon::Errors::NotFound, Fog::AWS::IAM::NotFound # ignore not found error + end + role + end + + def new(attributes = {}) + if not attributes.key?(:assume_role_policy_document) + attributes[:assume_role_policy_document] = Fog::AWS::IAM::EC2_ASSUME_ROLE_POLICY.to_s + end + super + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/user.rb b/lib/fog/aws/models/iam/user.rb new file mode 100644 index 000000000..04695abdf --- /dev/null +++ b/lib/fog/aws/models/iam/user.rb @@ -0,0 +1,38 @@ +require 'fog/core/model' + +module Fog + module AWS + class IAM + class User < Fog::Model + identity :id, :aliases => 'UserName' + attribute :path, :aliases => 'Path' + attribute :arn, :aliases => 'Arn' + attribute :user_id, :aliases => 'UserId' + attribute :created_at, :aliases => 'CreateDate', :type => :time + + def save + requires :id + data = service.create_user(id, path || '/').body['User'] + merge_attributes(data) + true + end + + def destroy + requires :id + service.delete_user(id) + true + end + + def policies + requires :id + service.policies(:username => id) + end + + def access_keys + requires :id + service.access_keys(:username => id) + end + end + end + end +end diff --git a/lib/fog/aws/models/iam/users.rb b/lib/fog/aws/models/iam/users.rb new file mode 100644 index 000000000..cfbc625ad --- /dev/null +++ b/lib/fog/aws/models/iam/users.rb @@ -0,0 +1,47 @@ +require 'fog/core/collection' +require 'fog/aws/models/iam/user' + +module Fog + module AWS + class IAM + class Users < Fog::Collection + attribute :is_truncated, :aliases => 'IsTruncated' + attribute :marker, :aliases => 'Marker' + + model Fog::AWS::IAM::User + + def all(options = {}) + merge_attributes(options) + data = service.list_users(options).body + merge_attributes('IsTruncated' => data['IsTruncated'], 'Marker' => data['Marker']) + load(data['Users']) # data is an array of attribute hashes + end + + def get(identity) + data = service.get_user(identity).body['User'] + new(data) # data is an attribute hash + rescue Fog::AWS::IAM::NotFound + nil + end + + alias_method :each_user_this_page, :each + + def each + if !block_given? + self + else + subset = dup.all + + subset.each_user_this_page {|f| yield f} + while subset.is_truncated + subset = subset.all('Marker' => subset.marker, 'MaxItems' => 1000) + subset.each_user_this_page {|f| yield f} + end + + self + end + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/event_subscription.rb b/lib/fog/aws/models/rds/event_subscription.rb new file mode 100644 index 000000000..b0dd87ee4 --- /dev/null +++ b/lib/fog/aws/models/rds/event_subscription.rb @@ -0,0 +1,41 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class EventSubscription < Fog::Model + identity :id, :aliases => 'CustSubscriptionId' + + attribute :event_categories, :aliases => 'EventCategories', :type => :array + attribute :source_type, :aliases => 'SourceType' + attribute :enabled, :aliases => 'Enabled' + attribute :status, :aliases => 'Status' + attribute :creation_time, :aliases => 'SubscriptionCreationTime' + attribute :sns_topic_arn, :aliases => 'SnsTopicArn' + + def ready? + ! ['deleting', 'creating'].include?(status) + end + + def destroy + service.delete_event_subscription(id) + reload + end + + def save + requires :id, :sns_topic_arn + + data = service.create_event_subscription( + 'EventCategories' => event_categories, + 'SourceType' => source_type, + 'Enabled' => enabled || true, + 'SubscriptionName' => id, + 'SnsTopicArn' => sns_topic_arn + ).body["CreateEventSubscriptionResult"]["EventSubscription"] + merge_attributes(data) + self + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/event_subscriptions.rb b/lib/fog/aws/models/rds/event_subscriptions.rb new file mode 100644 index 000000000..130d5a5ab --- /dev/null +++ b/lib/fog/aws/models/rds/event_subscriptions.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/event_subscription' + +module Fog + module AWS + class RDS + class EventSubscriptions < Fog::Collection + model Fog::AWS::RDS::EventSubscription + + def all + data = service.describe_event_subscriptions.body['DescribeEventSubscriptionsResult']['EventSubscriptionsList'] + load(data) + end + + def get(identity) + data = service.describe_event_subscriptions('SubscriptionName' => identity).body['DescribeEventSubscriptionsResult']['EventSubscriptionsList'] + new(data.first) + rescue Fog::AWS::RDS::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/instance_option.rb b/lib/fog/aws/models/rds/instance_option.rb new file mode 100644 index 000000000..e38abde52 --- /dev/null +++ b/lib/fog/aws/models/rds/instance_option.rb @@ -0,0 +1,18 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class InstanceOption < Fog::Model + attribute :multi_az_capable, :aliases => 'MultiAZCapable', :type => :boolean + attribute :engine, :aliases => 'Engine' + attribute :license_model, :aliases => 'LicenseModel' + attribute :read_replica_capable, :aliases => 'ReadReplicaCapable', :type => :boolean + attribute :engine_version, :aliases => 'EngineVersion' + attribute :availability_zones, :aliases => 'AvailabilityZones', :type => :array + attribute :db_instance_class, :aliases => 'DBInstanceClass' + attribute :vpc, :aliases => 'Vpc', :type => :boolean + end + end + end +end diff --git a/lib/fog/aws/models/rds/instance_options.rb b/lib/fog/aws/models/rds/instance_options.rb new file mode 100644 index 000000000..1e6c3d4d2 --- /dev/null +++ b/lib/fog/aws/models/rds/instance_options.rb @@ -0,0 +1,28 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/instance_option' + +module Fog + module AWS + class RDS + class InstanceOptions < Fog::PagedCollection + attribute :filters + attribute :engine + model Fog::AWS::RDS::InstanceOption + + def initialize(attributes) + self.filters ||= {} + super + end + + # This method deliberately returns only a single page of results + def all(filters_arg = filters) + filters.merge!(filters_arg) + + result = service.describe_orderable_db_instance_options(engine, filters).body['DescribeOrderableDBInstanceOptionsResult'] + filters[:marker] = result['Marker'] + load(result['OrderableDBInstanceOptions']) + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/log_file.rb b/lib/fog/aws/models/rds/log_file.rb new file mode 100644 index 000000000..58a66ec54 --- /dev/null +++ b/lib/fog/aws/models/rds/log_file.rb @@ -0,0 +1,22 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class LogFile < Fog::Model + attribute :rds_id, :aliases => 'DBInstanceIdentifier' + attribute :name, :aliases => 'LogFileName' + attribute :size, :aliases => 'Size', :type => :integer + attribute :last_written, :aliases => 'LastWritten', :type => :time + attribute :content, :aliases => 'LogFileData' + attribute :marker, :aliases => 'Marker' + attribute :more_content_available, :aliases => 'AdditionalDataPending', :type => :boolean + + def content_excerpt(marker=nil) + result = service.download_db_logfile_portion(self.rds_id, self.name, {:marker => marker}) + merge_attributes(result.body['DownloadDBLogFilePortionResult']) + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/log_files.rb b/lib/fog/aws/models/rds/log_files.rb new file mode 100644 index 000000000..9e94f0e53 --- /dev/null +++ b/lib/fog/aws/models/rds/log_files.rb @@ -0,0 +1,48 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/log_file' + +module Fog + module AWS + class RDS + class LogFiles < Fog::Collection + attribute :filters + attribute :rds_id + model Fog::AWS::RDS::LogFile + + def initialize(attributes) + self.filters ||= {} + super + end + + # This method deliberately returns only a single page of results + def all(filters_arg = filters) + filters.merge!(filters_arg) + + result = service.describe_db_log_files(rds_id, filters).body['DescribeDBLogFilesResult'] + filters[:marker] = result['Marker'] + load(result['DBLogFiles']) + end + + def each(filters_arg = filters) + if block_given? + begin + page = self.all(filters_arg) + # We need to explicitly use the base 'each' method here on the page, otherwise we get infinite recursion + base_each = Fog::Collection.instance_method(:each) + base_each.bind(page).call { |log_file| yield log_file } + end while self.filters[:marker] + end + self + end + + def get(file_name=nil) + if file_name + matches = self.select {|log_file| log_file.name.upcase == file_name.upcase} + return matches.first unless matches.empty? + end + rescue Fog::AWS::RDS::NotFound + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/parameter.rb b/lib/fog/aws/models/rds/parameter.rb new file mode 100644 index 000000000..23b539fbd --- /dev/null +++ b/lib/fog/aws/models/rds/parameter.rb @@ -0,0 +1,18 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class Parameter < Fog::Model + attribute :name, :aliases => ['ParameterName'] + attribute :data_type, :aliases => 'DataType' + attribute :description, :aliases => 'Description' + attribute :allowed_values, :aliases => 'AllowedValues' + attribute :source, :aliases => 'Source' + attribute :modifiable, :aliases => 'IsModifiable' + attribute :apply_type, :aliases => 'ApplyType' + attribute :value, :aliases => 'ParameterValue' + end + end + end +end diff --git a/lib/fog/aws/models/rds/parameter_group.rb b/lib/fog/aws/models/rds/parameter_group.rb new file mode 100644 index 000000000..cbceb938b --- /dev/null +++ b/lib/fog/aws/models/rds/parameter_group.rb @@ -0,0 +1,34 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class ParameterGroup < Fog::Model + identity :id, :aliases => ['DBParameterGroupName', :name] + attribute :family, :aliases => 'DBParameterGroupFamily' + attribute :description, :aliases => 'Description' + + def save + requires :family + requires :description + requires :id + service.create_db_parameter_group(id, family, description) + end + + def modify(changes) + service.modify_db_parameter_group id, changes.map {|c| {'ParameterName' => c[:name], 'ParameterValue' => c[:value], 'ApplyMethod' => c[:apply_method]}} + end + + def destroy + requires :id + service.delete_db_parameter_group(id) + true + end + + def parameters(filters={}) + service.parameters({:group => self}.merge(filters)) + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/parameter_groups.rb b/lib/fog/aws/models/rds/parameter_groups.rb new file mode 100644 index 000000000..8e74d9d3f --- /dev/null +++ b/lib/fog/aws/models/rds/parameter_groups.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/parameter_group' + +module Fog + module AWS + class RDS + class ParameterGroups < Fog::Collection + model Fog::AWS::RDS::ParameterGroup + + def all + data = service.describe_db_parameter_groups.body['DescribeDBParameterGroupsResult']['DBParameterGroups'] + load(data) # data is an array of attribute hashes + end + + def get(identity) + data = service.describe_db_parameter_groups(identity).body['DescribeDBParameterGroupsResult']['DBParameterGroups'].first + new(data) # data is an attribute hash + rescue Fog::AWS::RDS::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/parameters.rb b/lib/fog/aws/models/rds/parameters.rb new file mode 100644 index 000000000..bded209e0 --- /dev/null +++ b/lib/fog/aws/models/rds/parameters.rb @@ -0,0 +1,36 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/parameter' + +module Fog + module AWS + class RDS + class Parameters < Fog::Collection + attribute :group + attribute :filters + model Fog::AWS::RDS::Parameter + + def initialize(attributes) + self.filters ||= {} + if attributes[:source] + filters[:source] = attributes[:source] + end + super + end + + def all(filters_arg = filters) + filters = filters_arg + result = [] + marker = nil + finished = false + while !finished + data = service.describe_db_parameters(group.id, filters.merge(:marker => marker)).body + result.concat(data['DescribeDBParametersResult']['Parameters']) + marker = data['DescribeDBParametersResult']['Marker'] + finished = marker.nil? + end + load(result) # data is an array of attribute hashes + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/security_group.rb b/lib/fog/aws/models/rds/security_group.rb new file mode 100644 index 000000000..4ab35b06e --- /dev/null +++ b/lib/fog/aws/models/rds/security_group.rb @@ -0,0 +1,79 @@ +require 'fog/core/model' +require 'fog/core/current_machine' + +module Fog + module AWS + class RDS + class SecurityGroup < Fog::Model + identity :id, :aliases => ['DBSecurityGroupName'] + attribute :description, :aliases => 'DBSecurityGroupDescription' + attribute :ec2_security_groups, :aliases => 'EC2SecurityGroups', :type => :array + attribute :ip_ranges, :aliases => 'IPRanges', :type => :array + attribute :owner_id, :aliases => 'OwnerId' + + def ready? + (ec2_security_groups + ip_ranges).all?{|ingress| ingress['Status'] == 'authorized'} + end + + def destroy + requires :id + service.delete_db_security_group(id) + true + end + + def save + requires :id + requires :description + + data = service.create_db_security_group(id, description).body['CreateDBSecurityGroupResult']['DBSecurityGroup'] + merge_attributes(data) + true + end + + # group_owner_id defaults to the current owner_id + def authorize_ec2_security_group(group_name, group_owner_id=owner_id) + authorize_ingress({ + 'EC2SecurityGroupName' => group_name, + 'EC2SecurityGroupOwnerId' => group_owner_id + }) + end + + def authorize_cidrip(cidrip) + authorize_ingress({'CIDRIP' => cidrip}) + end + + # Add the current machine to the RDS security group. + def authorize_me + authorize_ip_address(Fog::CurrentMachine.ip_address) + end + + # Add the ip address to the RDS security group. + def authorize_ip_address(ip) + authorize_cidrip("#{ip}/32") + end + + def authorize_ingress(opts) + data = service.authorize_db_security_group_ingress(id, opts).body['AuthorizeDBSecurityGroupIngressResult']['DBSecurityGroup'] + merge_attributes(data) + end + + # group_owner_id defaults to the current owner_id + def revoke_ec2_security_group(group_name, group_owner_id=owner_id) + revoke_ingress({ + 'EC2SecurityGroupName' => group_name, + 'EC2SecurityGroupOwnerId' => group_owner_id + }) + end + + def revoke_cidrip(cidrip) + revoke_ingress({'CIDRIP' => cidrip}) + end + + def revoke_ingress(opts) + data = service.revoke_db_security_group_ingress(id, opts).body['RevokeDBSecurityGroupIngressResult']['DBSecurityGroup'] + merge_attributes(data) + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/security_groups.rb b/lib/fog/aws/models/rds/security_groups.rb new file mode 100644 index 000000000..13e74e22c --- /dev/null +++ b/lib/fog/aws/models/rds/security_groups.rb @@ -0,0 +1,41 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/security_group' + +module Fog + module AWS + class RDS + class SecurityGroups < Fog::Collection + attribute :server + attribute :filters + model Fog::AWS::RDS::SecurityGroup + + def initialize(attributes={}) + self.filters ||= {} + if attributes[:server] + filters[:identifier] = attributes[:server].id + end + super + end + + def all(filters_arg = filters) + filters = filters_arg + data = service.describe_db_security_groups(filters).body['DescribeDBSecurityGroupsResult']['DBSecurityGroups'] + load(data) # data is an array of attribute hashes + end + + # Example: + # get('my_db_security_group') # => model for my_db_security_group + def get(identity) + data = service.describe_db_security_groups(identity).body['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].first + new(data) # data is an attribute hash + rescue Fog::AWS::RDS::NotFound + nil + end + + def new(attributes = {}) + super + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/server.rb b/lib/fog/aws/models/rds/server.rb new file mode 100644 index 000000000..1269e3e2e --- /dev/null +++ b/lib/fog/aws/models/rds/server.rb @@ -0,0 +1,142 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class Server < Fog::Model + identity :id, :aliases => 'DBInstanceIdentifier' + attribute :engine, :aliases => 'Engine' + attribute :engine_version, :aliases => 'EngineVersion' + attribute :state, :aliases => 'DBInstanceStatus' + attribute :allocated_storage, :aliases => 'AllocatedStorage', :type => :integer + attribute :iops, :aliases => 'Iops' + attribute :availability_zone , :aliases => 'AvailabilityZone' + attribute :flavor_id, :aliases => 'DBInstanceClass' + attribute :endpoint, :aliases => 'Endpoint' + attribute :read_replica_source, :aliases => 'ReadReplicaSourceDBInstanceIdentifier' + attribute :read_replica_identifiers, :aliases => 'ReadReplicaDBInstanceIdentifiers', :type => :array + attribute :master_username, :aliases => 'MasterUsername' + attribute :multi_az, :aliases => 'MultiAZ' + attribute :created_at, :aliases => 'InstanceCreateTime', :type => :time + attribute :last_restorable_time, :aliases => 'LatestRestorableTime', :type => :time + attribute :auto_minor_version_upgrade, :aliases => 'AutoMinorVersionUpgrade' + attribute :pending_modified_values, :aliases => 'PendingModifiedValues' + attribute :preferred_backup_window, :aliases => 'PreferredBackupWindow' + attribute :preferred_maintenance_window, :aliases => 'PreferredMaintenanceWindow' + attribute :db_name, :aliases => 'DBName' + attribute :db_security_groups, :aliases => 'DBSecurityGroups', :type => :array + attribute :db_parameter_groups, :aliases => 'DBParameterGroups' + attribute :backup_retention_period, :aliases => 'BackupRetentionPeriod', :type => :integer + attribute :license_model, :aliases => 'LicenseModel' + attribute :db_subnet_group_name, :aliases => 'DBSubnetGroupName' + attribute :publicly_accessible, :aliases => 'PubliclyAccessible' + attribute :vpc_security_groups, :aliases => 'VpcSecurityGroups', :type => :array + attribute :storage_type, :aliases => 'StorageType' + + attr_accessor :password, :parameter_group_name, :security_group_names, :port + + def create_read_replica(replica_id, options={}) + options[:security_group_names] ||= options['DBSecurityGroups'] + params = self.class.new(options).attributes_to_params + service.create_db_instance_read_replica(replica_id, id, params) + service.servers.get(replica_id) + end + + def ready? + state == 'available' + end + + def destroy(snapshot_identifier=nil) + requires :id + service.delete_db_instance(id, snapshot_identifier, snapshot_identifier.nil?) + true + end + + def reboot + service.reboot_db_instance(id) + true + end + + def snapshots + requires :id + service.snapshots(:server => self) + end + + def tags + requires :id + service.list_tags_for_resource(id). + body['ListTagsForResourceResult']['TagList'] + end + + def add_tags(new_tags) + requires :id + service.add_tags_to_resource(id, new_tags) + tags + end + + def remove_tags(tag_keys) + requires :id + service.remove_tags_from_resource(id, tag_keys) + tags + end + + def promote_read_replica + requires :id + service.promote_read_replica(id) + end + + def modify(immediately, options) + options[:security_group_names] ||= options['DBSecurityGroups'] + params = self.class.new(options).attributes_to_params + data = service.modify_db_instance(id, immediately, params) + merge_attributes(data.body['ModifyDBInstanceResult']['DBInstance']) + true + end + + def save + requires :engine + requires :allocated_storage + requires :master_username + requires :password + + self.flavor_id ||= 'db.m1.small' + + data = service.create_db_instance(id, attributes_to_params) + merge_attributes(data.body['CreateDBInstanceResult']['DBInstance']) + true + end + + # Converts attributes to a parameter hash suitable for requests + def attributes_to_params + options = { + 'AllocatedStorage' => allocated_storage, + 'AutoMinorVersionUpgrade' => auto_minor_version_upgrade, + 'BackupRetentionPeriod' => backup_retention_period, + 'DBName' => db_name, + 'DBParameterGroupName' => parameter_group_name || attributes['DBParameterGroupName'], + 'DBSecurityGroups' => security_group_names, + 'DBInstanceIdentifier' => id, + 'AvailabilityZone' => availability_zone, + 'DBInstanceClass' => flavor_id, + 'Port' => port || attributes['Port'], + 'Engine' => engine, + 'EngineVersion' => engine_version, + 'Iops' => iops, + 'MasterUsername' => master_username, + 'MasterUserPassword' => password || attributes['MasterUserPassword'], + 'PreferredMaintenanceWindow' => preferred_maintenance_window, + 'PreferredBackupWindow' => preferred_backup_window, + 'MultiAZ' => multi_az, + 'LicenseModel' => license_model, + 'DBSubnetGroupName' => db_subnet_group_name, + 'PubliclyAccessible' => publicly_accessible, + 'VpcSecurityGroups' => vpc_security_groups, + 'StorageType' => storage_type, + } + + options.delete_if {|key, value| value.nil?} + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/servers.rb b/lib/fog/aws/models/rds/servers.rb new file mode 100644 index 000000000..d2925dd35 --- /dev/null +++ b/lib/fog/aws/models/rds/servers.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/server' + +module Fog + module AWS + class RDS + class Servers < Fog::Collection + model Fog::AWS::RDS::Server + + def all + data = service.describe_db_instances.body['DescribeDBInstancesResult']['DBInstances'] + load(data) # data is an array of attribute hashes + end + + def get(identity) + data = service.describe_db_instances(identity).body['DescribeDBInstancesResult']['DBInstances'].first + new(data) # data is an attribute hash + rescue Fog::AWS::RDS::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/snapshot.rb b/lib/fog/aws/models/rds/snapshot.rb new file mode 100644 index 000000000..0b809a76d --- /dev/null +++ b/lib/fog/aws/models/rds/snapshot.rb @@ -0,0 +1,49 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class Snapshot < Fog::Model + identity :id, :aliases => ['DBSnapshotIdentifier', :name] + attribute :instance_id, :aliases => 'DBInstanceIdentifier' + attribute :created_at, :aliases => 'SnapshotCreateTime', :type => :time + attribute :instance_created_at, :aliases => 'InstanceCreateTime', :type => :time + attribute :engine, :aliases => 'Engine' + attribute :engine_version, :aliases => 'EngineVersion' + attribute :master_username, :aliases => 'MasterUsername' + attribute :state, :aliases => 'Status' + attribute :port, :aliases => 'Port', :type => :integer + attribute :allocated_storage, :aliases => 'AllocatedStorage', :type => :integer + attribute :iops, :aliases => 'Iops', :type => :integer + attribute :availability_zone, :aliases => 'AvailabilityZone' + attribute :type, :aliases => 'SnapshotType' + attribute :publicly_accessible, :aliases => 'PubliclyAccessible' + + def ready? + state == 'available' + end + + def destroy + requires :id + + service.delete_db_snapshot(id) + true + end + + def save + requires :instance_id + requires :id + + data = service.create_db_snapshot(instance_id, id).body['CreateDBSnapshotResult']['DBSnapshot'] + merge_attributes(data) + true + end + + def server + requires :instance_id + service.servers.get(instance_id) + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/snapshots.rb b/lib/fog/aws/models/rds/snapshots.rb new file mode 100644 index 000000000..d059d06de --- /dev/null +++ b/lib/fog/aws/models/rds/snapshots.rb @@ -0,0 +1,69 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/snapshot' + +module Fog + module AWS + class RDS + class Snapshots < Fog::Collection + attribute :server + attribute :filters + model Fog::AWS::RDS::Snapshot + + def initialize(attributes) + self.filters ||= {} + if attributes[:server] + filters[:identifier] = attributes[:server].id + end + if attributes[:type] + filters[:type] = attributes[:type] + end + super + end + + # This method does NOT return all snapshots. Its implementation deliberately returns a single page + # of results for any one call. It will return a single page based on the current or provided filters, + # updating the filters with the marker for the next page. Calling this repeatedly will iterate + # through pages. See the implementation of each for an example of such iteration. + # + # It is arguably incorrect for the method not to return all snapshots, particularly considering the + # implementation in the corresponding 'elb' files. But this implementation has been released, and + # backwards-compatibility requires leaving it as implemented. + def all(filters_arg = filters) + filters.merge!(filters_arg) + + page = service.describe_db_snapshots(filters).body['DescribeDBSnapshotsResult'] + filters[:marker] = page['Marker'] + load(page['DBSnapshots']) + end + + # This will execute a block for each snapshot, fetching new pages of snapshots as required. + def each(filters_arg = filters) + if block_given? + begin + page = self.all(filters_arg) + # We need to explicitly use the base 'each' method here on the page, otherwise we get infinite recursion + base_each = Fog::Collection.instance_method(:each) + base_each.bind(page).call { |snapshot| yield snapshot } + end while self.filters[:marker] + end + self + end + + def get(identity) + data = service.describe_db_snapshots(:snapshot_id => identity).body['DescribeDBSnapshotsResult']['DBSnapshots'].first + new(data) # data is an attribute hash + rescue Fog::AWS::RDS::NotFound + nil + end + + def new(attributes = {}) + if server + super({ :instance_id => server.id }.merge!(attributes)) + else + super + end + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/subnet_group.rb b/lib/fog/aws/models/rds/subnet_group.rb new file mode 100644 index 000000000..37735f386 --- /dev/null +++ b/lib/fog/aws/models/rds/subnet_group.rb @@ -0,0 +1,31 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + class SubnetGroup < Fog::Model + identity :id, :aliases => ['DBSubnetGroupName', :name] + attribute :description, :aliases => 'DBSubnetGroupDescription' + attribute :status, :aliases => 'SubnetGroupStatus' + attribute :vpc_id, :aliases => 'VpcId' + attribute :subnet_ids, :aliases => 'Subnets' + + def ready? + requires :status + status == 'Complete' + end + + def save + requires :description, :id, :subnet_ids + service.create_db_subnet_group(id, subnet_ids, description) + reload + end + + def destroy + requires :id + service.delete_db_subnet_group(id) + end + end + end + end +end diff --git a/lib/fog/aws/models/rds/subnet_groups.rb b/lib/fog/aws/models/rds/subnet_groups.rb new file mode 100644 index 000000000..b1c76e1f0 --- /dev/null +++ b/lib/fog/aws/models/rds/subnet_groups.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/subnet_group' + +module Fog + module AWS + class RDS + class SubnetGroups < Fog::Collection + model Fog::AWS::RDS::SubnetGroup + + def all + data = service.describe_db_subnet_groups.body['DescribeDBSubnetGroupsResult']['DBSubnetGroups'] + load(data) # data is an array of attribute hashes + end + + def get(identity) + data = service.describe_db_subnet_groups(identity).body['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].first + new(data) # data is an attribute hash + rescue Fog::AWS::RDS::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/sns/subscription.rb b/lib/fog/aws/models/sns/subscription.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/fog/aws/models/sns/subscriptions.rb b/lib/fog/aws/models/sns/subscriptions.rb new file mode 100644 index 000000000..249ce327e --- /dev/null +++ b/lib/fog/aws/models/sns/subscriptions.rb @@ -0,0 +1,17 @@ +require 'fog/core/collection' +require 'fog/aws/models/sns/subscription' + +module Fog + module AWS + class SNS + class Subscriptions < Fog::Collection + model Fgo::AWS::SNS::Subscription + + def all + data = service.list_subscriptions.body["Subscriptions"] + load(data) + end + end + end + end +end diff --git a/lib/fog/aws/models/sns/topic.rb b/lib/fog/aws/models/sns/topic.rb new file mode 100644 index 000000000..d18d85293 --- /dev/null +++ b/lib/fog/aws/models/sns/topic.rb @@ -0,0 +1,48 @@ +require 'fog/core/model' + +module Fog + module AWS + class SNS + class Topic < Fog::Model + identity :id, :aliases => "TopicArn" + + attribute :owner, :aliases => "Owner" + attribute :policy, :aliases => "Policy" + attribute :display_name, :aliases => "DisplayName" + attribute :subscriptions_pending, :aliases => "SubscriptionsPending" + attribute :subscriptions_confirmed, :aliases => "SubscriptionsConfirmed" + attribute :subscriptions_deleted, :aliases => "SubscriptionsDeleted" + attribute :delivery_policy, :aliases => "DeliveryPolicy" + attribute :effective_delivery_policy, :aliases => "EffectiveDeliveryPolicy" + + def ready? + display_name + end + + def update_topic_attribute(attribute, new_value) + requires :id + service.set_topic_attributes(id, attribute, new_value).body + reload + end + + def destroy + requires :id + service.delete_topic(id) + true + end + + def save + requires :id + + data = service.create_topic(id).body["TopicArn"] + if data + data = {"id" => data} + merge_attributes(data) + true + else false + end + end + end + end + end +end diff --git a/lib/fog/aws/models/sns/topics.rb b/lib/fog/aws/models/sns/topics.rb new file mode 100644 index 000000000..82d2f3f14 --- /dev/null +++ b/lib/fog/aws/models/sns/topics.rb @@ -0,0 +1,24 @@ +require 'fog/core/collection' +require 'fog/aws/models/sns/topic' + +module Fog + module AWS + class SNS + class Topics < Fog::Collection + model Fog::AWS::SNS::Topic + + def all + data = service.list_topics.body["Topics"].map { |t| {"id" => t} } #This is an array, but it needs to be an array of hashes for #load + + load(data) + end + + def get(id) + if data = service.get_topic_attributes(id).body["Attributes"] + new(data) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/storage/directories.rb b/lib/fog/aws/models/storage/directories.rb new file mode 100644 index 000000000..533ca58f4 --- /dev/null +++ b/lib/fog/aws/models/storage/directories.rb @@ -0,0 +1,39 @@ +require 'fog/core/collection' +require 'fog/aws/models/storage/directory' + +module Fog + module Storage + class Aws + class Directories < Fog::Collection + model Fog::Storage::AWS::Directory + + def all + data = service.get_service.body['Buckets'] + load(data) + end + + def get(key, options = {}) + remap_attributes(options, { + :delimiter => 'delimiter', + :marker => 'marker', + :max_keys => 'max-keys', + :prefix => 'prefix' + }) + data = service.get_bucket(key, options).body + directory = new(:key => data['Name'], :is_persisted => true) + options = {} + for k, v in data + if ['CommonPrefixes', 'Delimiter', 'IsTruncated', 'Marker', 'MaxKeys', 'Prefix'].include?(k) + options[k] = v + end + end + directory.files.merge_attributes(options) + directory.files.load(data['Contents']) + directory + rescue Excon::Errors::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/aws/models/storage/directory.rb b/lib/fog/aws/models/storage/directory.rb new file mode 100644 index 000000000..9900665c7 --- /dev/null +++ b/lib/fog/aws/models/storage/directory.rb @@ -0,0 +1,126 @@ +require 'fog/core/model' +require 'fog/aws/models/storage/files' +require 'fog/aws/models/storage/versions' + +module Fog + module Storage + class Aws + class Directory < Fog::Model + VALID_ACLS = ['private', 'public-read', 'public-read-write', 'authenticated-read'] + + attr_reader :acl + + identity :key, :aliases => ['Name', 'name'] + + attribute :creation_date, :aliases => 'CreationDate', :type => 'time' + attribute :location, :aliases => 'LocationConstraint', :type => 'string' + + def acl=(new_acl) + unless VALID_ACLS.include?(new_acl) + raise ArgumentError.new("acl must be one of [#{VALID_ACLS.join(', ')}]") + else + @acl = new_acl + end + end + + def destroy + requires :key + service.delete_bucket(key) + true + rescue Excon::Errors::NotFound + false + end + + def location + @location ||= (bucket_location || self.service.region) + end + + # NOTE: you can't change the region once the bucket is created + def location=(new_location) + @location = new_location + end + + def files + @files ||= Fog::Storage::AWS::Files.new(:directory => self, :service => service) + end + + def payer + requires :key + data = service.get_request_payment(key) + data.body['Payer'] + end + + def payer=(new_payer) + requires :key + service.put_request_payment(key, new_payer) + @payer = new_payer + end + + def versioning? + requires :key + data = service.get_bucket_versioning(key) + data.body['VersioningConfiguration']['Status'] == 'Enabled' + end + + def versioning=(new_versioning) + requires :key + service.put_bucket_versioning(key, new_versioning ? 'Enabled' : 'Suspended') + end + + def versions + @versions ||= Fog::Storage::AWS::Versions.new(:directory => self, :service => service) + end + + def public=(new_public) + self.acl = new_public ? 'public-read' : 'private' + new_public + end + + def public_url + requires :key + if service.get_bucket_acl(key).body['AccessControlList'].find {|grant| grant['Grantee']['URI'] == 'http://acs.amazonaws.com/groups/global/AllUsers' && grant['Permission'] == 'READ'} + service.request_url( + :bucket_name => key + ) + else + nil + end + end + + def save + requires :key + + options = {} + + options['x-amz-acl'] = acl if acl + + # http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUT.html + # Ignore the default region us-east-1 + if !persisted? && location != DEFAULT_REGION + options['LocationConstraint'] = location + end + + service.put_bucket(key, options) + attributes[:is_persisted] = true + + true + end + + def persisted? + # is_persisted is true in case of directories.get or after #save + # creation_date is set in case of directories.all + attributes[:is_persisted] || !!attributes[:creation_date] + end + + private + + def bucket_location + requires :key + return nil unless persisted? + data = service.get_bucket_location(key) + data.body['LocationConstraint'] + end + end + end + end +end diff --git a/lib/fog/aws/models/storage/file.rb b/lib/fog/aws/models/storage/file.rb new file mode 100644 index 000000000..d89d4153a --- /dev/null +++ b/lib/fog/aws/models/storage/file.rb @@ -0,0 +1,280 @@ +require 'fog/core/model' +require 'fog/aws/models/storage/versions' + +module Fog + module Storage + class Aws + class File < Fog::Model + # @see Aws Object docs http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectOps.html + + identity :key, :aliases => 'Key' + + attr_writer :body + attribute :cache_control, :aliases => 'Cache-Control' + attribute :content_disposition, :aliases => 'Content-Disposition' + attribute :content_encoding, :aliases => 'Content-Encoding' + attribute :content_length, :aliases => ['Content-Length', 'Size'], :type => :integer + attribute :content_md5, :aliases => 'Content-MD5' + attribute :content_type, :aliases => 'Content-Type' + attribute :etag, :aliases => ['Etag', 'ETag'] + attribute :expires, :aliases => 'Expires' + attribute :last_modified, :aliases => ['Last-Modified', 'LastModified'] + attribute :metadata + attribute :owner, :aliases => 'Owner' + attribute :storage_class, :aliases => ['x-amz-storage-class', 'StorageClass'] + attribute :encryption, :aliases => 'x-amz-server-side-encryption' + attribute :version, :aliases => 'x-amz-version-id' + + # @note Chunk size to use for multipart uploads. + # Use small chunk sizes to minimize memory. E.g. 5242880 = 5mb + attr_accessor :multipart_chunk_size + + def acl + requires :directory, :key + service.get_object_acl(directory.key, key).body['AccessControlList'] + end + + # Set file's access control list (ACL). + # + # valid acls: private, public-read, public-read-write, authenticated-read, bucket-owner-read, bucket-owner-full-control + # + # @param [String] new_acl one of valid options + # @return [String] @acl + # + def acl=(new_acl) + valid_acls = ['private', 'public-read', 'public-read-write', 'authenticated-read', 'bucket-owner-read', 'bucket-owner-full-control'] + unless valid_acls.include?(new_acl) + raise ArgumentError.new("acl must be one of [#{valid_acls.join(', ')}]") + end + @acl = new_acl + end + + # Get file's body if exists, else ' '. + # + # @return [File] + # + def body + attributes[:body] ||= if last_modified && (file = collection.get(identity)) + file.body + else + '' + end + end + + # Set body attribute. + # + # @param [File] new_body + # @return [File] attributes[:body] + # + def body=(new_body) + attributes[:body] = new_body + end + + # Get the file instance's directory. + # + # @return [Fog::AWS::Storage::Directory] + # + def directory + @directory + end + + # Copy object from one bucket to other bucket. + # + # required attributes: directory, key + # + # @param target_directory_key [String] + # @param target_file_key [String] + # @param options [Hash] options for copy_object method + # @return [String] Fog::AWS::Files#head status of directory contents + # + def copy(target_directory_key, target_file_key, options = {}) + requires :directory, :key + service.copy_object(directory.key, key, target_directory_key, target_file_key, options) + target_directory = service.directories.new(:key => target_directory_key) + target_directory.files.head(target_file_key) + end + + # Destroy file via http DELETE. + # + # required attributes: directory, key + # + # @param options [Hash] + # @option options versionId [] + # @return [Boolean] true if successful + # + def destroy(options = {}) + requires :directory, :key + attributes[:body] = nil if options['versionId'] == version + service.delete_object(directory.key, key, options) + true + end + + remove_method :metadata + def metadata + attributes.reject {|key, value| !(key.to_s =~ /^x-amz-/)} + end + + remove_method :metadata= + def metadata=(new_metadata) + merge_attributes(new_metadata) + end + + remove_method :owner= + def owner=(new_owner) + if new_owner + attributes[:owner] = { + :display_name => new_owner['DisplayName'] || new_owner[:display_name], + :id => new_owner['ID'] || new_owner[:id] + } + end + end + + def public? + acl.any? {|grant| grant['Grantee']['URI'] == 'http://acs.amazonaws.com/groups/global/AllUsers' && grant['Permission'] == 'READ'} + end + + # Set Access-Control-List permissions. + # + # valid new_publics: public_read, private + # + # @param [String] new_public + # @return [String] new_public + # + def public=(new_public) + if new_public + @acl = 'public-read' + else + @acl = 'private' + end + new_public + end + + # Get publicly accessible url via http GET. + # Checks permissions before creating. + # Defaults to s3 subdomain or compliant bucket name + # + # required attributes: directory, key + # + # @return [String] public url + # + def public_url + requires :directory, :key + if public? + service.request_url( + :bucket_name => directory.key, + :object_name => key + ) + else + nil + end + end + + # Save file with body as contents to directory.key with name key via http PUT + # + # required attributes: body, directory, key + # + # @param [Hash] options + # @option options [String] acl sets x-amz-acl HTTP header. Valid values include, private | public-read | public-read-write | authenticated-read | bucket-owner-read | bucket-owner-full-control + # @option options [String] cache_control sets Cache-Control header. For example, 'No-cache' + # @option options [String] content_disposition sets Content-Disposition HTTP header. For exampple, 'attachment; filename=testing.txt' + # @option options [String] content_encoding sets Content-Encoding HTTP header. For example, 'x-gzip' + # @option options [String] content_md5 sets Content-MD5. For example, '79054025255fb1a26e4bc422aef54eb4' + # @option options [String] content_type Content-Type. For example, 'text/plain' + # @option options [String] expires sets number of seconds before Aws Object expires. + # @option options [String] storage_class sets x-amz-storage-class HTTP header. Defaults to 'STANDARD'. Or, 'REDUCED_REDUNDANCY' + # @option options [String] encryption sets HTTP encryption header. Set to 'AES256' to encrypt files at rest on S3 + # @return [Boolean] true if no errors + # + def save(options = {}) + requires :body, :directory, :key + if options != {} + Fog::Logger.deprecation("options param is deprecated, use acl= instead [light_black](#{caller.first})[/]") + end + options['x-amz-acl'] ||= @acl if @acl + options['Cache-Control'] = cache_control if cache_control + options['Content-Disposition'] = content_disposition if content_disposition + options['Content-Encoding'] = content_encoding if content_encoding + options['Content-MD5'] = content_md5 if content_md5 + options['Content-Type'] = content_type if content_type + options['Expires'] = expires if expires + options.merge!(metadata) + options['x-amz-storage-class'] = storage_class if storage_class + options['x-amz-server-side-encryption'] = encryption if encryption + + if multipart_chunk_size && body.respond_to?(:read) + data = multipart_save(options) + merge_attributes(data.body) + else + data = service.put_object(directory.key, key, body, options) + merge_attributes(data.headers.reject {|key, value| ['Content-Length', 'Content-Type'].include?(key)}) + end + self.etag.gsub!('"','') + self.content_length = Fog::Storage.get_body_size(body) + self.content_type ||= Fog::Storage.get_content_type(body) + true + end + + # Get a url for file. + # + # required attributes: key + # + # @param expires [String] number of seconds (since 1970-01-01 00:00) before url expires + # @param options [Hash] + # @return [String] url + # + def url(expires, options = {}) + requires :key + collection.get_url(key, expires, options) + end + + # File version if exists or creates new version. + # @return [Fog::Storage::AWS::Version] + # + def versions + @versions ||= begin + Fog::Storage::AWS::Versions.new( + :file => self, + :service => service + ) + end + end + + private + + def directory=(new_directory) + @directory = new_directory + end + + def multipart_save(options) + # Initiate the upload + res = service.initiate_multipart_upload(directory.key, key, options) + upload_id = res.body["UploadId"] + + # Store ETags of upload parts + part_tags = [] + + # Upload each part + # TODO: optionally upload chunks in parallel using threads + # (may cause network performance problems with many small chunks) + # TODO: Support large chunk sizes without reading the chunk into memory + if body.respond_to?(:rewind) + body.rewind rescue nil + end + while (chunk = body.read(multipart_chunk_size)) do + md5 = Base64.encode64(Digest::MD5.digest(chunk)).strip + part_upload = service.upload_part(directory.key, key, upload_id, part_tags.size + 1, chunk, 'Content-MD5' => md5 ) + part_tags << part_upload.headers["ETag"] + end + + rescue + # Abort the upload & reraise + service.abort_multipart_upload(directory.key, key, upload_id) if upload_id + raise + else + # Complete the upload + service.complete_multipart_upload(directory.key, key, upload_id, part_tags) + end + end + end + end +end diff --git a/lib/fog/aws/models/storage/files.rb b/lib/fog/aws/models/storage/files.rb new file mode 100644 index 000000000..606fe363e --- /dev/null +++ b/lib/fog/aws/models/storage/files.rb @@ -0,0 +1,119 @@ +require 'fog/core/collection' +require 'fog/aws/models/storage/file' + +module Fog + module Storage + class Aws + class Files < Fog::Collection + extend Fog::Deprecation + deprecate :get_url, :get_https_url + + attribute :common_prefixes, :aliases => 'CommonPrefixes' + attribute :delimiter, :aliases => 'Delimiter' + attribute :directory + attribute :is_truncated, :aliases => 'IsTruncated' + attribute :marker, :aliases => 'Marker' + attribute :max_keys, :aliases => ['MaxKeys', 'max-keys'] + attribute :prefix, :aliases => 'Prefix' + + model Fog::Storage::AWS::File + + def all(options = {}) + requires :directory + options = { + 'delimiter' => delimiter, + 'marker' => marker, + 'max-keys' => max_keys, + 'prefix' => prefix + }.merge!(options) + options = options.reject {|key,value| value.nil? || value.to_s.empty?} + merge_attributes(options) + parent = directory.collection.get( + directory.key, + options + ) + if parent + merge_attributes(parent.files.attributes) + load(parent.files.map {|file| file.attributes}) + else + nil + end + end + + alias_method :each_file_this_page, :each + def each + if !block_given? + self + else + subset = dup.all + + subset.each_file_this_page {|f| yield f} + while subset.is_truncated + subset = subset.all(:marker => subset.last.key) + subset.each_file_this_page {|f| yield f} + end + + self + end + end + + def get(key, options = {}, &block) + requires :directory + data = service.get_object(directory.key, key, options, &block) + normalize_headers(data) + file_data = data.headers.merge({ + :body => data.body, + :key => key + }) + new(file_data) + rescue Excon::Errors::NotFound => error + case error.response.body + when /NoSuchKey<\/Code>/ + nil + when /NoSuchBucket<\/Code>/ + raise(Fog::Storage::AWS::NotFound.new("Directory #{directory.identity} does not exist.")) + else + raise(error) + end + end + + def get_url(key, expires, options = {}) + requires :directory + service.get_object_url(directory.key, key, expires, options) + end + + def get_http_url(key, expires, options = {}) + requires :directory + service.get_object_http_url(directory.key, key, expires, options) + end + + def get_https_url(key, expires, options = {}) + requires :directory + service.get_object_https_url(directory.key, key, expires, options) + end + + def head(key, options = {}) + requires :directory + data = service.head_object(directory.key, key, options) + normalize_headers(data) + file_data = data.headers.merge({ + :key => key + }) + new(file_data) + rescue Excon::Errors::NotFound + nil + end + + def new(attributes = {}) + requires :directory + super({ :directory => directory }.merge!(attributes)) + end + + def normalize_headers(data) + data.headers['Last-Modified'] = Time.parse(data.get_header('Last-Modified')) + data.headers['ETag'] = data.get_header('ETag').gsub('"','') + end + end + end + end +end diff --git a/lib/fog/aws/models/storage/version.rb b/lib/fog/aws/models/storage/version.rb new file mode 100644 index 000000000..d663877e4 --- /dev/null +++ b/lib/fog/aws/models/storage/version.rb @@ -0,0 +1,33 @@ +require 'fog/core/model' + +module Fog + module Storage + class Aws + class Version < Fog::Model + identity :version, :aliases => 'VersionId' + + attribute :key, :aliases => 'Key' + attribute :last_modified, :aliases => ['Last-Modified', 'LastModified'] + attribute :latest, :aliases => 'IsLatest', :type => :boolean + attribute :content_length, :aliases => ['Content-Length', 'Size'], :type => :integer + attribute :delete_marker, :type => :boolean + + def file + @file ||= if collection.file + collection.file.directory.files.get(key, 'versionId' => version) + else + collection.directory.files.get(key, 'versionId' => version) + end + end + + def destroy + if collection.file + collection.service.delete_object(collection.file.directory.key, key, 'versionId' => version) + else + collection.service.delete_object(collection.directory.key, key, 'versionId' => version) + end + end + end + end + end +end diff --git a/lib/fog/aws/models/storage/versions.rb b/lib/fog/aws/models/storage/versions.rb new file mode 100644 index 000000000..a574d2cb4 --- /dev/null +++ b/lib/fog/aws/models/storage/versions.rb @@ -0,0 +1,34 @@ +require 'fog/core/collection' +require 'fog/aws/models/storage/version' + +module Fog + module Storage + class Aws + class Versions < Fog::Collection + attribute :file + attribute :directory + + model Fog::Storage::AWS::Version + + def all(options = {}) + data = if file + service.get_bucket_object_versions(file.directory.key, options.merge('prefix' => file.key)).body['Versions'] + else + service.get_bucket_object_versions(directory.key, options).body['Versions'] + end + + load(data) + end + + def new(attributes = {}) + version_type = attributes.keys.first + + model = super(attributes[version_type]) + model.delete_marker = version_type == 'DeleteMarker' + + model + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/basic.rb b/lib/fog/aws/parsers/auto_scaling/basic.rb new file mode 100644 index 000000000..0f1518760 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/basic.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class Basic < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_adjustment_types.rb b/lib/fog/aws/parsers/auto_scaling/describe_adjustment_types.rb new file mode 100644 index 000000000..e50e79a47 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_adjustment_types.rb @@ -0,0 +1,49 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeAdjustmentTypes < Fog::Parsers::Base + def reset + reset_adjustment_type + @results = { 'AdjustmentTypes' => [] } + @response = { 'DescribeAdjustmentTypesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_adjustment_type + @adjustment_type = {} + end + + def start_element(name, attrs = []) + super + case name + when 'AdjustmentTypes' + @in_adjustment_types = true + end + end + + def end_element(name) + case name + when 'member' + if @in_adjustment_types + @results['AdjustmentTypes'] << @adjustment_type + reset_adjustment_type + end + + when 'AdjustmentType' + @adjustment_type[name] = value + + when 'AdjustmentTypes' + @in_adjustment_types = false + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeAdjustmentTypesResponse' + @response['DescribeAdjustmentTypesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_groups.rb b/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_groups.rb new file mode 100644 index 000000000..79c48ce67 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_groups.rb @@ -0,0 +1,156 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeAutoScalingGroups < Fog::Parsers::Base + def reset + reset_auto_scaling_group + reset_enabled_metric + reset_instance + reset_suspended_process + reset_tag + @results = { 'AutoScalingGroups' => [] } + @response = { 'DescribeAutoScalingGroupsResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_auto_scaling_group + @auto_scaling_group = { + 'AvailabilityZones' => [], + 'EnabledMetrics' => [], + 'Instances' => [], + 'LoadBalancerNames' => [], + 'SuspendedProcesses' => [], + 'Tags' => [], + 'TerminationPolicies' => [] + } + end + + def reset_enabled_metric + @enabled_metric = {} + end + + def reset_instance + @instance = {} + end + + def reset_suspended_process + @suspended_process = {} + end + + def reset_tag + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'member' + when 'AvailabilityZones' + @in_availability_zones = true + when 'EnabledMetrics' + @in_enabled_metrics = true + when 'Instances' + @in_instances = true + when 'LoadBalancerNames' + @in_load_balancer_names = true + when 'SuspendedProcesses' + @in_suspended_processes = true + when 'Tags' + @in_tags = true + when 'TerminationPolicies' + @in_termination_policies = true + end + end + + def end_element(name) + case name + when 'member' + if @in_availability_zones + @auto_scaling_group['AvailabilityZones'] << value + elsif @in_enabled_metrics + @auto_scaling_group['EnabledMetrics'] << @enabled_metric + reset_enabled_metric + elsif @in_instances + @auto_scaling_group['Instances'] << @instance + reset_instance + elsif @in_load_balancer_names + @auto_scaling_group['LoadBalancerNames'] << value + elsif @in_suspended_processes + @auto_scaling_group['SuspendedProcesses'] << @suspended_process + reset_suspended_process + elsif @in_tags + @auto_scaling_group['Tags'] << @tag + reset_tag + elsif @in_termination_policies + @auto_scaling_group['TerminationPolicies'] << value + else + @results['AutoScalingGroups'] << @auto_scaling_group + reset_auto_scaling_group + end + + when 'AvailabilityZones' + @in_availability_zones = false + + when 'Granularity', 'Metric' + @enabled_metric[name] = value + when 'EnabledMetrics' + @in_enabled_metrics = false + + when 'AvailabilityZone', 'HealthStatus', 'InstanceId', 'LifecycleState' + @instance[name] = value + when 'Instances' + @in_instances = false + + when 'LoadBalancerNames' + @in_load_balancer_names = false + + when 'ProcessName', 'SuspensionReason' + @suspended_process[name] = value + when 'SuspendedProcesses' + @in_suspended_processes = false + + when 'Key', 'ResourceId', 'ResourceType', 'Value' + @tag[name] = value + when 'PropagateAtLaunch' + @tag[name] = (value == 'true') + when 'Tags' + @in_tags = false + + when 'TerminationPolicies' + @in_termination_policies = false + + when 'LaunchConfigurationName' + if @in_instances + @instance[name] = value + else + @auto_scaling_group[name] = value + end + + when 'AutoScalingGroupARN', 'AutoScalingGroupName' + @auto_scaling_group[name] = value + when 'CreatedTime' + @auto_scaling_group[name] = Time.parse(value) + when 'DefaultCooldown', 'DesiredCapacity', 'HealthCheckGracePeriod' + @auto_scaling_group[name] = value.to_i + when 'HealthCheckType' + @auto_scaling_group[name] = value + when 'MaxSize', 'MinSize' + @auto_scaling_group[name] = value.to_i + when 'PlacementGroup', 'VPCZoneIdentifier' + @auto_scaling_group[name] = value + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeAutoScalingGroupsResponse' + @response['DescribeAutoScalingGroupsResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_instances.rb b/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_instances.rb new file mode 100644 index 000000000..8866bba76 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_instances.rb @@ -0,0 +1,40 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeAutoScalingInstances < Fog::Parsers::Base + def reset + reset_auto_scaling_instance + @results = { 'AutoScalingInstances' => [] } + @response = { 'DescribeAutoScalingInstancesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_auto_scaling_instance + @auto_scaling_instance = {} + end + + def end_element(name) + case name + when 'member' + @results['AutoScalingInstances'] << @auto_scaling_instance + reset_auto_scaling_instance + + when 'AutoScalingGroupName', 'AvailabilityZone', 'HealthStatus', + 'InstanceId', 'LaunchConfigurationName', 'LifecycleState' + @auto_scaling_instance[name] = value + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeAutoScalingInstancesResponse' + @response['DescribeAutoScalingInstancesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_notification_types.rb b/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_notification_types.rb new file mode 100644 index 000000000..2b2b6df05 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_auto_scaling_notification_types.rb @@ -0,0 +1,40 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeAutoScalingNotificationTypes < Fog::Parsers::Base + def reset + @results = { 'AutoScalingNotificationTypes' => [] } + @response = { 'DescribeAutoScalingNotificationTypesResult' => {}, 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + case name + when 'AutoScalingNotificationTypes' + @in_auto_scaling_notification_types = true + end + end + + def end_element(name) + case name + when 'member' + if @in_auto_scaling_notification_types + @results['AutoScalingNotificationTypes'] << value + end + + when 'AutoScalingNotificationTypes' + @in_auto_scaling_notification_types = false + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeAutoScalingNotificationTypesResponse' + @response['DescribeAutoScalingNotificationTypesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_launch_configurations.rb b/lib/fog/aws/parsers/auto_scaling/describe_launch_configurations.rb new file mode 100644 index 000000000..ab14f7c6a --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_launch_configurations.rb @@ -0,0 +1,97 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeLaunchConfigurations < Fog::Parsers::Base + def reset + reset_launch_configuration + reset_block_device_mapping + reset_ebs + @results = { 'LaunchConfigurations' => [] } + @response = { 'DescribeLaunchConfigurationsResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_launch_configuration + @launch_configuration = { 'BlockDeviceMappings' => [], 'InstanceMonitoring' => {}, 'SecurityGroups' => [] } + end + + def reset_block_device_mapping + @block_device_mapping = {} + end + + def reset_ebs + @ebs = {} + end + + def start_element(name, attrs = []) + super + case name + when 'BlockDeviceMappings' + @in_block_device_mappings = true + when 'SecurityGroups' + @in_security_groups = true + end + end + + def end_element(name) + case name + when 'member' + if @in_block_device_mappings + @launch_configuration['BlockDeviceMappings'] << @block_device_mapping + reset_block_device_mapping + elsif @in_security_groups + @launch_configuration['SecurityGroups'] << value + else + @results['LaunchConfigurations'] << @launch_configuration + reset_launch_configuration + end + + when 'DeviceName', 'VirtualName' + @block_device_mapping[name] = value + + when 'SnapshotId', 'VolumeSize' + @ebs[name] = value + when 'Ebs' + @block_device_mapping[name] = @ebs + reset_ebs + + when 'Enabled' + @launch_configuration['InstanceMonitoring'][name] = (value == 'true') + + when 'CreatedTime' + @launch_configuration[name] = Time.parse(value) + when 'ImageId', 'InstanceType', 'KeyName' + @launch_configuration[name] = value + when 'LaunchConfigurationARN', 'LaunchConfigurationName' + @launch_configuration[name] = value + when 'KernelId', 'RamdiskId', 'UserData' + @launch_configuration[name] = value + when 'IamInstanceProfile' + @launch_configuration[name] = value + when 'SpotPrice' + @launch_configuration[name] = value.to_f + + when 'AssociatePublicIpAddress' + @in_associate_public_ip = false + when 'BlockDeviceMappings' + @in_block_device_mappings = false + when 'LaunchConfigurations' + @in_launch_configurations = false + when 'SecurityGroups' + @in_security_groups = false + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeLaunchConfigurationsResponse' + @response['DescribeLaunchConfigurationsResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_metric_collection_types.rb b/lib/fog/aws/parsers/auto_scaling/describe_metric_collection_types.rb new file mode 100644 index 000000000..6e5581543 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_metric_collection_types.rb @@ -0,0 +1,64 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeMetricCollectionTypes < Fog::Parsers::Base + def reset + reset_granularity + reset_metric + @results = { 'Granularities' => [], 'Metrics' => [] } + @response = { 'DescribeMetricCollectionTypesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_granularity + @granularity = {} + end + + def reset_metric + @metric = {} + end + + def start_element(name, attrs = []) + super + + case name + when 'Granularities' + @in_granularities = true + when 'Metrics' + @in_metrics = true + end + end + + def end_element(name) + case name + when 'member' + if @in_granularities + @results['Granularities'] << @granularity + reset_granularity + elsif @in_metrics + @results['Metrics'] << @metric + reset_metric + end + + when 'Granularity' + @granularity[name] = value + when 'Granularities' + @in_granularities = false + + when 'Metric' + @metric[name] = value + when 'Metrics' + @in_metrics = false + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeMetricCollectionTypesResult' + @response[name] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_notification_configurations.rb b/lib/fog/aws/parsers/auto_scaling/describe_notification_configurations.rb new file mode 100644 index 000000000..9792aeb61 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_notification_configurations.rb @@ -0,0 +1,39 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeNotificationConfigurations < Fog::Parsers::Base + def reset + reset_notification_configuration + @results = { 'NotificationConfigurations' => [] } + @response = { 'DescribeNotificationConfigurationsResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_notification_configuration + @notification_configuration = {} + end + + def end_element(name) + case name + when 'member' + @results['NotificationConfigurations'] << @notification_configuration + reset_notification_configuration + + when 'AutoScalingGroupName','NotificationType', 'TopicARN' + @notification_configuration[name] = value + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeNotificationConfigurationsResponse' + @response['DescribeNotificationConfigurationsResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_policies.rb b/lib/fog/aws/parsers/auto_scaling/describe_policies.rb new file mode 100644 index 000000000..a8357c5e7 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_policies.rb @@ -0,0 +1,65 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribePolicies < Fog::Parsers::Base + def reset + reset_scaling_policy + reset_alarm + @results = { 'ScalingPolicies' => [] } + @response = { 'DescribePoliciesResult' => {}, 'ResponseMetadata' => {} } + @in_alarms = false + end + + def reset_scaling_policy + @scaling_policy = { 'Alarms' => [] } + end + + def reset_alarm + @alarm = {} + end + + def start_element(name, attrs = []) + super + case name + when 'Alarms' + @in_alarms = true + end + end + + def end_element(name) + case name + when 'AlarmARN', 'AlarmName' + @alarm[name] = value + + when 'AdjustmentType', 'AutoScalingGroupName', 'PolicyARN', 'PolicyName' + @scaling_policy[name] = value + when 'Cooldown', 'MinAdjustmentStep', 'ScalingAdjustment' + @scaling_policy[name] = value.to_i + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribePoliciesResponse' + @response['DescribePoliciesResult'] = @results + + when 'Alarms' + @in_alarms = false + when 'member' + if @in_alarms + @scaling_policy['Alarms'] << @alarm + reset_alarm + else + @results['ScalingPolicies'] << @scaling_policy + reset_scaling_policy + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_scaling_activities.rb b/lib/fog/aws/parsers/auto_scaling/describe_scaling_activities.rb new file mode 100644 index 000000000..0c52abb54 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_scaling_activities.rb @@ -0,0 +1,44 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeScalingActivities < Fog::Parsers::Base + def reset + reset_activity + @results = { 'Activities' => [] } + @response = { 'DescribeScalingActivitiesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_activity + @activity = {} + end + + def end_element(name) + case name + when 'member' + @results['Activities'] << @activity + reset_activity + + when 'ActivityId', 'AutoScalingGroupName', 'Cause', 'Description', + 'StatusCode', 'StatusMessage' + @activity[name] = value + when 'EndTime', 'StartTime' + @activity[name] = Time.parse(value) + when 'Progress' + @activity[name] = value.to_i + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeScalingActivitiesResponse' + @response['DescribeScalingActivitiesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_scaling_process_types.rb b/lib/fog/aws/parsers/auto_scaling/describe_scaling_process_types.rb new file mode 100644 index 000000000..0d3feaff0 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_scaling_process_types.rb @@ -0,0 +1,49 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeScalingProcessTypes < Fog::Parsers::Base + def reset + reset_process_type + @results = { 'Processes' => [] } + @response = { 'DescribeScalingProcessTypesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_process_type + @process_type = {} + end + + def start_element(name, attrs = []) + super + case name + when 'Processes' + @in_processes = true + end + end + + def end_element(name) + case name + when 'member' + if @in_processes + @results['Processes'] << @process_type + reset_process_type + end + + when 'ProcessName' + @process_type[name] = value + + when 'Processes' + @in_processes = false + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeScalingProcessTypesResponse' + @response['DescribeScalingProcessTypesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_scheduled_actions.rb b/lib/fog/aws/parsers/auto_scaling/describe_scheduled_actions.rb new file mode 100644 index 000000000..ed9265792 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_scheduled_actions.rb @@ -0,0 +1,43 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeScheduledActions < Fog::Parsers::Base + def reset + reset_scheduled_update_group_action + @results = { 'ScheduledUpdateGroupActions' => [] } + @response = { 'DescribeScheduledActionsResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_scheduled_update_group_action + @scheduled_update_group_action = {} + end + + def end_element(name) + case name + when 'member' + @results['ScheduledUpdateGroupActions'] << @scheduled_update_group_action + reset_scheduled_update_group_action + + when 'AutoScalingGroupName', 'ScheduledActionARN', 'ScheduledActionName', 'Recurrence' + @scheduled_update_group_action[name] = value + when 'DesiredCapacity', 'MaxSize', 'MinSize' + @scheduled_update_group_action[name] = value.to_i + when 'Time', 'StartTime', 'EndTime' + @scheduled_update_group_action[name] = Time.parse(value) + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeScheduledActionsResponse' + @response['DescribeScheduledActionsResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_tags.rb b/lib/fog/aws/parsers/auto_scaling/describe_tags.rb new file mode 100644 index 000000000..27a550027 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_tags.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeTags < Fog::Parsers::Base + def reset + reset_tag + @results = { 'Tags' => [] } + @response = { 'DescribeTagsResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_tag + @tag = {} + end + + def end_element(name) + case name + when 'member' + @results['Tags'] << @tag + reset_tag + + when 'Key', 'ResourceId', 'ResourceType', 'Value' + @tag[name] = value + when 'PropagateAtLaunch' + @tag[name] = (value == 'true') + + when 'NextToken' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeTagsResponse' + @response['DescribeTagsResult'] = @results + + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/describe_termination_policy_types.rb b/lib/fog/aws/parsers/auto_scaling/describe_termination_policy_types.rb new file mode 100644 index 000000000..9b2cc2c55 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/describe_termination_policy_types.rb @@ -0,0 +1,40 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class DescribeTerminationPolicyTypes < Fog::Parsers::Base + def reset + @results = { 'TerminationPolicyTypes' => [] } + @response = { 'DescribeTerminationPolicyTypesResult' => {}, 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + case name + when 'TerminationPolicyTypes' + @in_termination_policy_types = true + end + end + + def end_element(name) + case name + when 'member' + if @in_termination_policy_types + @results['TerminationPolicyTypes'] << value + end + + when 'TerminationPolicyTypes' + @in_termination_policy_types = false + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeTerminationPolicyTypesResponse' + @response['DescribeTerminationPolicyTypesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/put_notification_configuration.rb b/lib/fog/aws/parsers/auto_scaling/put_notification_configuration.rb new file mode 100644 index 000000000..eef6a956d --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/put_notification_configuration.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class PutNotificationConfiguration < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/put_scaling_policy.rb b/lib/fog/aws/parsers/auto_scaling/put_scaling_policy.rb new file mode 100644 index 000000000..4a0b53126 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/put_scaling_policy.rb @@ -0,0 +1,27 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class PutScalingPolicy < Fog::Parsers::Base + def reset + @results = {} + @response = { 'PutScalingPolicyResult' => {}, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'PolicyARN' + @results[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'PutScalingPolicyResponse' + @response['PutScalingPolicyResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/auto_scaling/terminate_instance_in_auto_scaling_group.rb b/lib/fog/aws/parsers/auto_scaling/terminate_instance_in_auto_scaling_group.rb new file mode 100644 index 000000000..ebc63aa50 --- /dev/null +++ b/lib/fog/aws/parsers/auto_scaling/terminate_instance_in_auto_scaling_group.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module AutoScaling + class TerminateInstanceInAutoScalingGroup < Fog::Parsers::Base + def reset + @results = { 'Activity' => {} } + @response = { 'TerminateInstanceInAutoScalingGroupResult' => {}, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'ActivityId', 'AutoScalingGroupName', 'Cause', + 'Description', 'StatusCode', 'StatusMessage' + @results['Activity'][name] = value + when 'EndTime', 'StartTime' + @results['Activity'][name] = Time.parse(value) + when 'Progress' + @results['Activity'][name] = value.to_i + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'TerminateInstanceInAutoScalingGroupResponse' + @response['TerminateInstanceInAutoScalingGroupResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/check_dns_availability.rb b/lib/fog/aws/parsers/beanstalk/check_dns_availability.rb new file mode 100644 index 000000000..06192e995 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/check_dns_availability.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class CheckDNSAvailability < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("CheckDNSAvailabilityResult") + tag 'FullyQualifiedCNAME', :string + tag 'Available', :boolean + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/create_application.rb b/lib/fog/aws/parsers/beanstalk/create_application.rb new file mode 100644 index 000000000..81bdd6d8c --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/create_application.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class CreateApplication < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("CreateApplicationResult") + tag 'Application', :object + tag 'Versions', :string, :list + tag 'ConfigurationTemplates', :string, :list + tag 'ApplicationName', :string + tag 'Description', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/create_application_version.rb b/lib/fog/aws/parsers/beanstalk/create_application_version.rb new file mode 100644 index 000000000..d1001f599 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/create_application_version.rb @@ -0,0 +1,23 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class CreateApplicationVersion < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("CreateApplicationVersionResult") + tag 'ApplicationVersion', :object + tag 'ApplicationName', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'SourceBundle', :object + tag 'S3Bucket', :string + tag 'S3Key', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/create_configuration_template.rb b/lib/fog/aws/parsers/beanstalk/create_configuration_template.rb new file mode 100644 index 000000000..563768ba3 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/create_configuration_template.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class CreateConfigurationTemplate < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("CreateConfigurationTemplateResult") + tag 'ApplicationName', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'DeploymentStatus', :string + tag 'Description', :string + tag 'EnvironmentName', :string + tag 'OptionSettings', :object, :list + tag 'Namespace', :string + tag 'OptionName', :string + tag 'Value', :string + tag 'SolutionStackName', :string + tag 'TemplateName', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/create_environment.rb b/lib/fog/aws/parsers/beanstalk/create_environment.rb new file mode 100644 index 000000000..3ff53f777 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/create_environment.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class CreateEnvironment < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("CreateEnvironmentResult") + tag 'ApplicationName', :string + tag 'CNAME', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'EndpointURL', :string + tag 'EnvironmentId', :string + tag 'EnvironmentName', :string + tag 'Health', :string + tag 'Resources', :object + tag 'LoadBalancer', :object + tag 'Domain', :string + tag 'LoadBalancerName', :string + tag 'Listeners', :object, :list + tag 'Port', :integer + tag 'Protocol', :string + tag 'SolutionStackName', :string + tag 'Status', :string + tag 'TemplateName', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/create_storage_location.rb b/lib/fog/aws/parsers/beanstalk/create_storage_location.rb new file mode 100644 index 000000000..9530a88d4 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/create_storage_location.rb @@ -0,0 +1,15 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class CreateStorageLocation < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("CreateStorageLocationResult") + tag 'S3Bucket', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_application_versions.rb b/lib/fog/aws/parsers/beanstalk/describe_application_versions.rb new file mode 100644 index 000000000..6da6f5b07 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_application_versions.rb @@ -0,0 +1,23 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeApplicationVersions < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeApplicationVersionsResult") + tag 'ApplicationVersions', :object, :list + tag 'ApplicationName', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'SourceBundle', :object + tag 'S3Bucket', :string + tag 'S3Key', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_applications.rb b/lib/fog/aws/parsers/beanstalk/describe_applications.rb new file mode 100644 index 000000000..55a6efb74 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_applications.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeApplications < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeApplicationsResult") + tag 'Applications', :object, :list + tag 'Versions', :string, :list + tag 'ConfigurationTemplates', :string, :list + tag 'ApplicationName', :string + tag 'Description', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_configuration_options.rb b/lib/fog/aws/parsers/beanstalk/describe_configuration_options.rb new file mode 100644 index 000000000..5400a0946 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_configuration_options.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeConfigurationOptions < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeConfigurationOptionsResult") + tag 'SolutionStackName', :string + tag 'Options', :object, :list + tag 'ChangeSeverity', :string + tag 'DefaultValue', :string + tag 'MaxLength', :integer + tag 'MaxValue', :integer + tag 'MinValue', :integer + tag 'Name', :string + tag 'Namespace', :string + tag 'Regex', :object + tag 'Label', :string + tag 'Pattern', :string + tag 'UserDefined', :boolean + tag 'ValueOptions', :string, :list + tag 'ValueType', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_configuration_settings.rb b/lib/fog/aws/parsers/beanstalk/describe_configuration_settings.rb new file mode 100644 index 000000000..78fc145b0 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_configuration_settings.rb @@ -0,0 +1,27 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeConfigurationSettings < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeConfigurationSettingsResult") + tag 'ConfigurationSettings', :object, :list + tag 'ApplicationName', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'DeploymentStatus', :string + tag 'Description', :string + tag 'EnvironmentName', :string + tag 'OptionSettings', :object, :list + tag 'Namespace', :string + tag 'OptionName', :string + tag 'Value', :string + tag 'SolutionStackName', :string + tag 'TemplateName', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_environment_resources.rb b/lib/fog/aws/parsers/beanstalk/describe_environment_resources.rb new file mode 100644 index 000000000..e3b1bec1d --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_environment_resources.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeEnvironmentResources < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeEnvironmentResourcesResult") + tag 'EnvironmentResources', :object + tag 'AutoScalingGroups', :object, :list + tag 'Name', :string + tag 'EnvironmentName', :string + tag 'Instances', :object, :list + tag 'Id', :string + tag 'LaunchConfigurations', :object, :list + tag 'LoadBalancers', :object, :list + tag 'Resources', :object, :list + tag 'Description', :string + tag 'LogicalResourceId', :string + tag 'PhysicalResourceId', :string + tag 'Type', :string + tag 'Properties', :object, :list + tag 'RuntimeSources', :object, :list + tag 'Parameter', :string + tag 'Versions', :object, :list + tag 'ApplicationName', :string + tag 'VersionLabel', :string + tag 'Triggers', :object, :list + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_environments.rb b/lib/fog/aws/parsers/beanstalk/describe_environments.rb new file mode 100644 index 000000000..f6908254d --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_environments.rb @@ -0,0 +1,35 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeEnvironments < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeEnvironmentsResult") + tag 'Environments', :object, :list + tag 'ApplicationName', :string + tag 'CNAME', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'EndpointURL', :string + tag 'EnvironmentId', :string + tag 'EnvironmentName', :string + tag 'Health', :string + tag 'Resources', :object + tag 'LoadBalancer', :object + tag 'Domain', :string + tag 'LoadBalancerName', :string + tag 'Listeners', :object, :list + tag 'Port', :integer + tag 'Protocol', :string + tag 'SolutionStackName', :string + tag 'Status', :string + tag 'TemplateName', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/describe_events.rb b/lib/fog/aws/parsers/beanstalk/describe_events.rb new file mode 100644 index 000000000..6c60d4f55 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/describe_events.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class DescribeEvents < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("DescribeEventsResult") + tag 'Events', :object, :list + tag 'ApplicationName', :string + tag 'EnvironmentName', :string + tag 'EventDate', :datetime + tag 'Message', :string + tag 'RequestId', :string + tag 'Severity', :string + tag 'TemplateName', :string + tag 'VersionLabel', :string + tag 'NextToken', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/empty.rb b/lib/fog/aws/parsers/beanstalk/empty.rb new file mode 100644 index 000000000..614a8e480 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/empty.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + class Empty < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/list_available_solution_stacks.rb b/lib/fog/aws/parsers/beanstalk/list_available_solution_stacks.rb new file mode 100644 index 000000000..1b453415e --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/list_available_solution_stacks.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class ListAvailableSolutionStacks < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("ListAvailableSolutionStacksResult") + tag 'SolutionStackDetails', :object, :list + tag 'PermittedFileTypes', :string, :list + tag 'SolutionStackName', :string + tag 'SolutionStacks', :string, :list + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/parser.rb b/lib/fog/aws/parsers/beanstalk/parser.rb new file mode 100644 index 000000000..aac9e261c --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/parser.rb @@ -0,0 +1,84 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + class BaseParser < Fog::Parsers::Base + def initialize(result_name) + @result_name = result_name # Set before super, since super calls reset + super() + @tags = {} + @list_tags = {} + end + + def reset + @response = { @result_name => {}, 'ResponseMetadata' => {} } + # Push root object to top of stack + @parse_stack = [ { :type => :object, :value => @response[@result_name]} ] + end + + def tag name, *traits + if traits.delete(:list) + @list_tags[name] = true + end + + if traits.length == 1 + @tags[name] = traits.last + else + raise "Too many traits specified, only specify :list or a type" + end + end + + def start_element(name, attrs = []) + super + if name == 'member' + if @parse_stack.last[:type] == :object + @parse_stack.last[:value] << {} # Push any empty object + end + elsif @list_tags.key?(name) + set_value(name, [], :array) # Set an empty array + @parse_stack.push({ :type => @tags[name], :value => get_parent[name] }) + elsif @tags[name] == :object + set_value(name, {}, :object) + @parse_stack.push({ :type => @tags[name], :value => get_parent[name] }) + end + end + + def end_element(name) + case name + when 'member' + if @parse_stack.last[:type] != :object + @parse_stack.last[:value] << value + end + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + if @list_tags.key?(name) || @tags[name] == :object + @parse_stack.pop() + elsif @tags.key?(name) + set_value(name, value, @tags[name]) + end + end + end + + def get_parent + parent = @parse_stack.last[:value] + parent.is_a?(Array) ? parent.last : parent + end + + def set_value(name, value, type) + case type + when :datetime + get_parent[name] = Time.parse value + when :boolean + get_parent[name] = value == "true" # True only if value is true + when :integer + get_parent[name] = value.to_i + else + get_parent[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/retrieve_environment_info.rb b/lib/fog/aws/parsers/beanstalk/retrieve_environment_info.rb new file mode 100644 index 000000000..0a2868326 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/retrieve_environment_info.rb @@ -0,0 +1,19 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class RetrieveEnvironmentInfo < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("RetrieveEnvironmentInfoResult") + tag 'EnvironmentInfo', :object, :list + tag 'Ec2InstanceId', :string + tag 'InfoType', :string + tag 'Message', :string + tag 'SampleTimestamp', :datetime + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/terminate_environment.rb b/lib/fog/aws/parsers/beanstalk/terminate_environment.rb new file mode 100644 index 000000000..cf0be2b2e --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/terminate_environment.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class TerminateEnvironment < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("TerminateEnvironmentResult") + tag 'ApplicationName', :string + tag 'CNAME', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'EndpointURL', :string + tag 'EnvironmentId', :string + tag 'EnvironmentName', :string + tag 'Health', :string + tag 'Resources', :object + tag 'LoadBalancer', :object + tag 'Domain', :string + tag 'LoadBalancerName', :string + tag 'Listeners', :object, :list + tag 'Port', :integer + tag 'Protocol', :string + tag 'SolutionStackName', :string + tag 'Status', :string + tag 'TemplateName', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/update_application.rb b/lib/fog/aws/parsers/beanstalk/update_application.rb new file mode 100644 index 000000000..bc63aa5a3 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/update_application.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class UpdateApplication < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("UpdateApplicationResult") + tag 'Application', :object + tag 'Versions', :string, :list + tag 'ConfigurationTemplates', :string, :list + tag 'ApplicationName', :string + tag 'Description', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/update_application_version.rb b/lib/fog/aws/parsers/beanstalk/update_application_version.rb new file mode 100644 index 000000000..212cca414 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/update_application_version.rb @@ -0,0 +1,23 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class UpdateApplicationVersion < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("UpdateApplicationVersionResult") + tag 'ApplicationVersion', :object + tag 'ApplicationName', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'SourceBundle', :object + tag 'S3Bucket', :string + tag 'S3Key', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/update_configuration_template.rb b/lib/fog/aws/parsers/beanstalk/update_configuration_template.rb new file mode 100644 index 000000000..a0bad2ba7 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/update_configuration_template.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class UpdateConfigurationTemplate < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("UpdateConfigurationTemplateResult") + tag 'ApplicationName', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'DeploymentStatus', :string + tag 'Description', :string + tag 'EnvironmentName', :string + tag 'OptionSettings', :object, :list + tag 'Namespace', :string + tag 'OptionName', :string + tag 'Value', :string + tag 'SolutionStackName', :string + tag 'TemplateName', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/update_environment.rb b/lib/fog/aws/parsers/beanstalk/update_environment.rb new file mode 100644 index 000000000..df6259b97 --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/update_environment.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class UpdateEnvironment < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("UpdateEnvironmentResult") + tag 'ApplicationName', :string + tag 'CNAME', :string + tag 'DateCreated', :datetime + tag 'DateUpdated', :datetime + tag 'Description', :string + tag 'EndpointURL', :string + tag 'EnvironmentId', :string + tag 'EnvironmentName', :string + tag 'Health', :string + tag 'Resources', :object + tag 'LoadBalancer', :object + tag 'Domain', :string + tag 'LoadBalancerName', :string + tag 'Listeners', :object, :list + tag 'Port', :integer + tag 'Protocol', :string + tag 'SolutionStackName', :string + tag 'Status', :string + tag 'TemplateName', :string + tag 'VersionLabel', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/beanstalk/validate_configuration_settings.rb b/lib/fog/aws/parsers/beanstalk/validate_configuration_settings.rb new file mode 100644 index 000000000..a279eac0c --- /dev/null +++ b/lib/fog/aws/parsers/beanstalk/validate_configuration_settings.rb @@ -0,0 +1,19 @@ +module Fog + module Parsers + module AWS + module ElasticBeanstalk + require 'fog/aws/parsers/beanstalk/parser' + class ValidateConfigurationSettings < Fog::Parsers::AWS::ElasticBeanstalk::BaseParser + def initialize + super("ValidateConfigurationSettingsResult") + tag 'Messages', :object, :list + tag 'Message', :string + tag 'Namespace', :string + tag 'OptionName', :string + tag 'Severity', :string + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/distribution.rb b/lib/fog/aws/parsers/cdn/distribution.rb new file mode 100644 index 000000000..e9caa9890 --- /dev/null +++ b/lib/fog/aws/parsers/cdn/distribution.rb @@ -0,0 +1,55 @@ +module Fog + module Parsers + module CDN + module AWS + class Distribution < Fog::Parsers::Base + def reset + @response = { 'DistributionConfig' => { 'CNAME' => [], 'Logging' => {}, 'TrustedSigners' => [] } } + end + + def start_element(name, attrs = []) + super + case name + when 'CustomOrigin', 'S3Origin' + @origin = name + @response['DistributionConfig'][@origin] = {} + end + end + + def end_element(name) + case name + when 'AwsAccountNumber' + @response['DistributionConfig']['TrustedSigners'] << value + when 'Bucket', 'Prefix' + @response['DistributionConfig']['Logging'][name] = value + when 'CNAME' + @response['DistributionConfig']['CNAME'] << value + when 'DNSName', 'OriginAccessIdentity', 'OriginProtocolPolicy' + @response['DistributionConfig'][@origin][name] = value + when 'DomainName', 'Id', 'Status' + @response[name] = value + when 'CallerReference', 'Comment', 'DefaultRootObject', 'Origin', 'OriginAccessIdentity' + @response['DistributionConfig'][name] = value + when 'Enabled' + if value == 'true' + @response['DistributionConfig'][name] = true + else + @response['DistributionConfig'][name] = false + end + when 'HTTPPort', 'HTTPSPort' + @response['DistributionConfig'][@origin][name] = value.to_i + when 'InProgressInvalidationBatches' + @response[name] = value.to_i + when 'LastModifiedTime' + @response[name] = Time.parse(value) + when 'Protocol' + @response['DistributionConfig']['RequireProtocols'] = value + when 'Self' + @response['DistributionConfig']['TrustedSigners'] << 'Self' + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/get_distribution_list.rb b/lib/fog/aws/parsers/cdn/get_distribution_list.rb new file mode 100644 index 000000000..fdd3df6d1 --- /dev/null +++ b/lib/fog/aws/parsers/cdn/get_distribution_list.rb @@ -0,0 +1,57 @@ +module Fog + module Parsers + module CDN + module AWS + class GetDistributionList < Fog::Parsers::Base + def reset + @distribution_summary = { 'CNAME' => [], 'TrustedSigners' => [] } + @response = { 'DistributionSummary' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'CustomOrigin', 'S3Origin' + @origin = name + @distribution_summary[@origin] = {} + end + end + + def end_element(name) + case name + when 'DistributionSummary' + @response['DistributionSummary'] << @distribution_summary + @distribution_summary = { 'CNAME' => [], 'TrustedSigners' => [] } + when 'Comment', 'DomainName', 'Id', 'Origin', 'Status' + @distribution_summary[name] = value + when 'CNAME' + @distribution_summary[name] << value + when 'DNSName', 'OriginAccessIdentity', 'OriginProtocolPolicy' + @distribution_summary[@origin][name] = value + when 'Enabled' + if value == 'true' + @distribution_summary[name] = true + else + @distribution_summary[name] = false + end + when 'HTTPPort', 'HTTPSPort' + @distribution_summary[@origin][name] = value.to_i + when 'LastModifiedTime' + @distribution_summary[name] = Time.parse(value) + when 'IsTruncated' + if value == 'true' + @response[name] = true + else + @response[name] = false + end + when 'Marker', 'NextMarker' + @response[name] = value + when 'MaxItems' + @response[name] = value.to_i + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/get_invalidation.rb b/lib/fog/aws/parsers/cdn/get_invalidation.rb new file mode 100644 index 000000000..54d41811b --- /dev/null +++ b/lib/fog/aws/parsers/cdn/get_invalidation.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module CDN + module AWS + class GetInvalidation < Fog::Parsers::Base + def reset + @response = { 'InvalidationBatch' => { 'Path' => [] } } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'Path' + @response['InvalidationBatch'][name] << value + when 'Id', 'Status', 'CreateTime' + @response[name] = value + when 'CallerReference' + @response['InvalidationBatch'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/get_invalidation_list.rb b/lib/fog/aws/parsers/cdn/get_invalidation_list.rb new file mode 100644 index 000000000..44e425ef5 --- /dev/null +++ b/lib/fog/aws/parsers/cdn/get_invalidation_list.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module CDN + module AWS + class GetInvalidationList < Fog::Parsers::Base + def reset + @invalidation_summary = { } + @response = { 'InvalidationSummary' => [] } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'InvalidationSummary' + @response['InvalidationSummary'] << @invalidation_summary + @invalidation_summary = {} + when 'Id', 'Status' + @invalidation_summary[name] = @value + when 'IsTruncated' + if @value == 'true' + @response[name] = true + else + @response[name] = false + end + when 'Marker', 'NextMarker' + @response[name] = @value + when 'MaxItems' + @response[name] = @value.to_i + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/get_streaming_distribution_list.rb b/lib/fog/aws/parsers/cdn/get_streaming_distribution_list.rb new file mode 100644 index 000000000..6b51c1b56 --- /dev/null +++ b/lib/fog/aws/parsers/cdn/get_streaming_distribution_list.rb @@ -0,0 +1,55 @@ +module Fog + module Parsers + module CDN + module AWS + class GetStreamingDistributionList < Fog::Parsers::Base + def reset + @distribution_summary = { 'CNAME' => [], 'TrustedSigners' => [] } + @response = { 'StreamingDistributionSummary' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'S3Origin' + @origin = name + @distribution_summary[@origin] = {} + end + end + + def end_element(name) + case name + when 'StreamingDistributionSummary' + @response['StreamingDistributionSummary'] << @distribution_summary + @distribution_summary = { 'CNAME' => [], 'TrustedSigners' => [] } + when 'Comment', 'DomainName', 'Id', 'Status' + @distribution_summary[name] = @value + when 'CNAME' + @distribution_summary[name] << @value + when 'DNSName', 'OriginAccessIdentity' + @distribution_summary[@origin][name] = @value + when 'Enabled' + if @value == 'true' + @distribution_summary[name] = true + else + @distribution_summary[name] = false + end + when 'LastModifiedTime' + @distribution_summary[name] = Time.parse(@value) + when 'IsTruncated' + if @value == 'true' + @response[name] = true + else + @response[name] = false + end + when 'Marker', 'NextMarker' + @response[name] = @value + when 'MaxItems' + @response[name] = @value.to_i + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/post_invalidation.rb b/lib/fog/aws/parsers/cdn/post_invalidation.rb new file mode 100644 index 000000000..1ad0efe3c --- /dev/null +++ b/lib/fog/aws/parsers/cdn/post_invalidation.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module CDN + module AWS + class PostInvalidation < Fog::Parsers::Base + def reset + @response = { 'InvalidationBatch' => { 'Path' => [] } } + end + + def end_element(name) + case name + when 'CallerReference' + @response['InvalidationBatch'][name] = value + when 'CreateTime', 'Id', 'Status' + @response[name] = value + when 'Path' + @response['InvalidationBatch'][name] << value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cdn/streaming_distribution.rb b/lib/fog/aws/parsers/cdn/streaming_distribution.rb new file mode 100644 index 000000000..709d5a61e --- /dev/null +++ b/lib/fog/aws/parsers/cdn/streaming_distribution.rb @@ -0,0 +1,56 @@ +module Fog + module Parsers + module CDN + module AWS + + class StreamingDistribution < Fog::Parsers::Base + def reset + @response = { 'StreamingDistributionConfig' => { 'CNAME' => [], 'Logging' => {}, 'TrustedSigners' => [] } } + end + + def start_element(name, attrs = []) + super + case name + when 'CustomOrigin', 'S3Origin' + @origin = name + @response['StreamingDistributionConfig'][@origin] = {} + end + end + + def end_element(name) + case name + when 'AwsAccountNumber' + @response['StreamingDistributionConfig']['TrustedSigners'] << @value + when 'Bucket', 'Prefix' + @response['StreamingDistributionConfig']['Logging'][name] = @value + when 'CNAME' + @response['StreamingDistributionConfig']['CNAME'] << @value + when 'DNSName', 'OriginAccessIdentity', 'OriginProtocolPolicy' + @response['StreamingDistributionConfig'][@origin][name] = @value + when 'DomainName', 'Id', 'Status' + @response[name] = @value + when 'CallerReference', 'Comment', 'DefaultRootObject', 'Origin', 'OriginAccessIdentity' + @response['StreamingDistributionConfig'][name] = @value + when 'Enabled' + if @value == 'true' + @response['StreamingDistributionConfig'][name] = true + else + @response['StreamingDistributionConfig'][name] = false + end + when 'HTTPPort', 'HTTPSPort' + @response['StreamingDistributionConfig'][@origin][name] = @value.to_i + when 'InProgressInvalidationBatches' + @response[name] = @value.to_i + when 'LastModifiedTime' + @response[name] = Time.parse(@value) + when 'Protocol' + @response['StreamingDistributionConfig']['RequireProtocols'] = @value + when 'Self' + @response['StreamingDistributionConfig']['TrustedSigners'] << 'Self' + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/basic.rb b/lib/fog/aws/parsers/cloud_formation/basic.rb new file mode 100644 index 000000000..92761e5bf --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/basic.rb @@ -0,0 +1,10 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class Basic < Fog::Parsers::Base + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/create_stack.rb b/lib/fog/aws/parsers/cloud_formation/create_stack.rb new file mode 100644 index 000000000..953593809 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/create_stack.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class CreateStack < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId', 'StackId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/describe_stack_events.rb b/lib/fog/aws/parsers/cloud_formation/describe_stack_events.rb new file mode 100644 index 000000000..018f47daf --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/describe_stack_events.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class DescribeStackEvents < Fog::Parsers::Base + def reset + @event = {} + @response = { 'StackEvents' => [] } + end + + def end_element(name) + case name + when 'EventId', 'LogicalResourceId', 'PhysicalResourceId', 'ResourceProperties', 'ResourceStatus', 'ResourceStatusReason', 'ResourceType', 'StackId', 'StackName' + @event[name] = value + when 'member' + @response['StackEvents'] << @event + @event = {} + when 'RequestId' + @response[name] = value + when 'Timestamp' + @event[name] = Time.parse(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/describe_stack_resources.rb b/lib/fog/aws/parsers/cloud_formation/describe_stack_resources.rb new file mode 100644 index 000000000..b8a697ec4 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/describe_stack_resources.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class DescribeStackResources < Fog::Parsers::Base + def reset + @resource = {} + @response = { 'StackResources' => [] } + end + + def end_element(name) + case name + when 'StackId', 'StackName', 'LogicalResourceId', 'PhysicalResourceId', 'ResourceType', 'ResourceStatus' + @resource[name] = value + when 'member' + @response['StackResources'] << @resource + @resource = {} + when 'RequestId' + @response[name] = value + when 'Timestamp' + @resource[name] = Time.parse(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/describe_stacks.rb b/lib/fog/aws/parsers/cloud_formation/describe_stacks.rb new file mode 100644 index 000000000..fe25cf524 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/describe_stacks.rb @@ -0,0 +1,78 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class DescribeStacks < Fog::Parsers::Base + def reset + @stack = { 'Outputs' => [], 'Parameters' => [], 'Capabilities' => [] } + @output = {} + @parameter = {} + @response = { 'Stacks' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Outputs' + @in_outputs = true + when 'Parameters' + @in_parameters = true + when 'Capabilities' + @in_capabilities = true + end + end + + def end_element(name) + if @in_outputs + case name + when 'OutputKey', 'OutputValue', 'Description' + @output[name] = value + when 'member' + @stack['Outputs'] << @output + @output = {} + when 'Outputs' + @in_outputs = false + end + elsif @in_parameters + case name + when 'ParameterKey', 'ParameterValue' + @parameter[name] = value + when 'member' + @stack['Parameters'] << @parameter + @parameter = {} + when 'Parameters' + @in_parameters = false + end + elsif @in_capabilities + case name + when 'member' + @stack['Capabilities'] << value + when 'Capabilities' + @in_capabilities = false + end + else + case name + when 'member' + @response['Stacks'] << @stack + @stack = { 'Outputs' => [], 'Parameters' => [], 'Capabilities' => []} + when 'RequestId' + @response[name] = value + when 'CreationTime' + @stack[name] = Time.parse(value) + when 'DisableRollback' + case value + when 'false' + @stack[name] = false + when 'true' + @stack[name] = true + end + when 'StackName', 'StackId', 'StackStatus' + @stack[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/get_template.rb b/lib/fog/aws/parsers/cloud_formation/get_template.rb new file mode 100644 index 000000000..80acd6ec4 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/get_template.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class GetTemplate < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId', 'TemplateBody' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/list_stack_resources.rb b/lib/fog/aws/parsers/cloud_formation/list_stack_resources.rb new file mode 100644 index 000000000..a1d50803c --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/list_stack_resources.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class ListStackResources < Fog::Parsers::Base + def reset + @resource = {} + @response = { 'StackResourceSummaries' => [] } + end + + def end_element(name) + case name + when 'ResourceStatus', 'LogicalResourceId', 'PhysicalResourceId', 'ResourceType' + @resource[name] = value + when 'member' + @response['StackResourceSummaries'] << @resource + @resource = {} + when 'LastUpdatedTimestamp' + @resource[name] = Time.parse(value) + when 'RequestId' + @response[name] = value + when 'NextToken' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/list_stacks.rb b/lib/fog/aws/parsers/cloud_formation/list_stacks.rb new file mode 100644 index 000000000..47ec99539 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/list_stacks.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class ListStacks < Fog::Parsers::Base + def reset + @stack = {} + @response = { 'StackSummaries' => [] } + end + + def end_element(name) + case name + when 'StackId', 'StackStatus', 'StackName', 'TemplateDescription' + @stack[name] = value + when 'member' + @response['StackSummaries'] << @stack + @stack = {} + when 'RequestId' + @response[name] = value + when 'CreationTime' + @stack[name] = Time.parse(value) + when 'DeletionTime' + @stack[name] = Time.parse(value) + when 'NextToken' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/update_stack.rb b/lib/fog/aws/parsers/cloud_formation/update_stack.rb new file mode 100644 index 000000000..0e3c3115d --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/update_stack.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class UpdateStack < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId', 'StackId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_formation/validate_template.rb b/lib/fog/aws/parsers/cloud_formation/validate_template.rb new file mode 100644 index 000000000..fa16430bc --- /dev/null +++ b/lib/fog/aws/parsers/cloud_formation/validate_template.rb @@ -0,0 +1,49 @@ +module Fog + module Parsers + module AWS + module CloudFormation + class ValidateTemplate < Fog::Parsers::Base + def reset + @parameter = {} + @response = { 'Parameters' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Parameters' + @in_parameters = true + end + end + + def end_element(name) + case name + when 'DefaultValue', 'ParameterKey' + @parameter[name] = value + when 'Description' + if @in_parameters + @parameter[name] = value + else + @response[name] = value + end + when 'RequestId' + @response[name] = value + when 'member' + @response['Parameters'] << @parameter + @parameter = {} + when 'NoEcho' + case value + when 'false' + @parameter[name] = false + when 'true' + @parameter[name] = true + end + when 'Parameters' + @in_parameters = false + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/delete_alarms.rb b/lib/fog/aws/parsers/cloud_watch/delete_alarms.rb new file mode 100644 index 000000000..ba76119fb --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/delete_alarms.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class DeleteAlarms < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/describe_alarm_history.rb b/lib/fog/aws/parsers/cloud_watch/describe_alarm_history.rb new file mode 100644 index 000000000..6d0329cf1 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/describe_alarm_history.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class DescribeAlarmHistory < Fog::Parsers::Base + def reset + @response = { 'DescribeAlarmHistoryResult' => {'AlarmHistoryItems' => []}, 'ResponseMetadata' => {} } + reset_alarm_history_item + end + + def reset_alarm_history_item + @alarm_history_item = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'AlarmName', 'HistoryItemType', 'HistorySummary' + @alarm_history_item[name] = value + when 'Timestamp' + @alarm_history_item[name] = Time.parse value + when 'RequestId' + @response['ResponseMetadata'][name] = value + when 'NextToken' + @response['ResponseMetadata'][name] = value + when 'member' + @response['DescribeAlarmHistoryResult']['AlarmHistoryItems'] << @alarm_history_item + reset_alarm_history_item + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/describe_alarms.rb b/lib/fog/aws/parsers/cloud_watch/describe_alarms.rb new file mode 100644 index 000000000..ecf70960c --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/describe_alarms.rb @@ -0,0 +1,71 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class DescribeAlarms < Fog::Parsers::Base + def reset + @response = { 'DescribeAlarmsResult' => {'MetricAlarms' => []}, 'ResponseMetadata' => {} } + reset_metric_alarms + end + + def reset_metric_alarms + @metric_alarms = {'Dimensions' => []} + end + + def reset_dimension + @dimension = {} + end + + def start_element(name, attrs = []) + super + case name + when 'Dimensions' + @in_dimensions = true + when 'member' + if @in_dimensions + reset_dimension + end + end + end + + def end_element(name) + case name + when 'Name', 'Value' + @dimension[name] = value + when 'AlarmConfigurationUpdatedTimestamp', 'StateUpdatedTimestamp' + @metric_alarms[name] = Time.parse value + when 'Period', 'EvaluationPeriods' + @metric_alarms[name] = value.to_i + when 'Threshold' + @metric_alarms[name] = value.to_f + when 'AlarmActions', 'OKActions', 'InsufficientDataActions' + @metric_alarms[name] = value.to_s.strip + when 'AlarmName', 'Namespace', 'MetricName', 'AlarmDescription', 'AlarmArn', 'Unit', + 'StateValue', 'Statistic', 'ComparisonOperator', 'StateReason', 'ActionsEnabled' + @metric_alarms[name] = value + when 'StateUpdatedTimestamp', 'AlarmConfigurationUpdatedTimestamp' + @metric_alarms[name] = Time.parse value + when 'Dimensions' + @in_dimensions = false + when 'RequestId' + @response['ResponseMetadata'][name] = value + when 'NextToken' + @response['ResponseMetadata'][name] = value + when 'member' + if !@in_dimensions + if @metric_alarms.key?('AlarmName') + @response['DescribeAlarmsResult']['MetricAlarms'] << @metric_alarms + reset_metric_alarms + elsif @response['DescribeAlarmsResult']['MetricAlarms'].last != nil + @response['DescribeAlarmsResult']['MetricAlarms'].last.merge!( @metric_alarms) + end + else + @metric_alarms['Dimensions'] << @dimension + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/describe_alarms_for_metric.rb b/lib/fog/aws/parsers/cloud_watch/describe_alarms_for_metric.rb new file mode 100644 index 000000000..457d91057 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/describe_alarms_for_metric.rb @@ -0,0 +1,69 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class DescribeAlarmsForMetric < Fog::Parsers::Base + def reset + @response = { 'DescribeAlarmsForMetricResult' => {'MetricAlarms' => []}, 'ResponseMetadata' => {} } + reset_metric_alarms + end + + def reset_metric_alarms + @metric_alarms = {'Dimensions' => []} + end + + def reset_dimension + @dimension = {} + end + + def start_element(name, attrs = []) + super + case name + when 'Dimensions' + @in_dimensions = true + when 'member' + if @in_dimensions + reset_dimension + end + end + end + + def end_element(name) + case name + when 'Name', 'Value' + @dimension[name] = value + when 'Period', 'EvaluationPeriods' + @metric_alarms[name] = value.to_i + when 'Threshold' + @metric_alarms[name] = value.to_f + when 'AlarmActions', 'OKActions', 'InsufficientDataActions' + @metric_alarms[name] = value.to_s.strip + when 'AlarmName', 'Namespace', 'MetricName', 'AlarmDescription', 'AlarmArn', 'Unit', + 'StateValue', 'Statistic', 'ComparisonOperator', 'StateReason', 'ActionsEnabled' + @metric_alarms[name] = value + when 'StateUpdatedTimestamp', 'AlarmConfigurationUpdatedTimestamp' + @metric_alarms[name] = Time.parse value + when 'Dimensions' + @in_dimensions = false + when 'NextToken' + @response['ResponseMetadata'][name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + when 'member' + if !@in_dimensions + if @metric_alarms.key?('AlarmName') + @response['DescribeAlarmsForMetricResult']['MetricAlarms'] << @metric_alarms + reset_metric_alarms + elsif @response['DescribeAlarmsForMetricResult']['MetricAlarms'].last != nil + @response['DescribeAlarmsForMetricResult']['MetricAlarms'].last.merge!( @metric_alarms) + end + else + @metric_alarms['Dimensions'] << @dimension + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/disable_alarm_actions.rb b/lib/fog/aws/parsers/cloud_watch/disable_alarm_actions.rb new file mode 100644 index 000000000..d7c2d919f --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/disable_alarm_actions.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class DisableAlarmActions < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/enable_alarm_actions.rb b/lib/fog/aws/parsers/cloud_watch/enable_alarm_actions.rb new file mode 100644 index 000000000..a9049f115 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/enable_alarm_actions.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class EnableAlarmActions < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/get_metric_statistics.rb b/lib/fog/aws/parsers/cloud_watch/get_metric_statistics.rb new file mode 100644 index 000000000..c9a4408ee --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/get_metric_statistics.rb @@ -0,0 +1,40 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class GetMetricStatistics < Fog::Parsers::Base + def reset + @response = { 'GetMetricStatisticsResult' => {'Datapoints' => []}, 'ResponseMetadata' => {} } + reset_datapoint + end + + def reset_datapoint + @datapoint = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'Average', 'Maximum', 'Minimum', 'SampleCount', 'Sum' + @datapoint[name] = value.to_f + when 'Unit' + @datapoint[name] = value + when 'Timestamp' + @datapoint[name] = Time.parse value + when 'member' + @response['GetMetricStatisticsResult']['Datapoints'] << @datapoint + reset_datapoint + when 'Label' + @response['GetMetricStatisticsResult'][name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/list_metrics.rb b/lib/fog/aws/parsers/cloud_watch/list_metrics.rb new file mode 100644 index 000000000..fd701e543 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/list_metrics.rb @@ -0,0 +1,56 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class ListMetrics < Fog::Parsers::Base + def reset + @response = { 'ListMetricsResult' => {'Metrics' => []}, 'ResponseMetadata' => {} } + reset_metric + end + + def reset_metric + @metric = {'Dimensions' => []} + end + + def reset_dimension + @dimension = {} + end + + def start_element(name, attrs = []) + super + case name + when 'Dimensions' + @in_dimensions = true + when 'member' + if @in_dimensions + reset_dimension + end + end + end + + def end_element(name) + case name + when 'Name', 'Value' + @dimension[name] = value + when 'Namespace', 'MetricName' + @metric[name] = value + when 'Dimensions' + @in_dimensions = false + when 'NextMarker', 'NextToken' + @response['ListMetricsResult'][name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + when 'member' + if !@in_dimensions + @response['ListMetricsResult']['Metrics'] << @metric + reset_metric + else + @metric['Dimensions'] << @dimension + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/put_metric_alarm.rb b/lib/fog/aws/parsers/cloud_watch/put_metric_alarm.rb new file mode 100644 index 000000000..075b5aac1 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/put_metric_alarm.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class PutMetricAlarm < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value.strip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/put_metric_data.rb b/lib/fog/aws/parsers/cloud_watch/put_metric_data.rb new file mode 100644 index 000000000..97707dd99 --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/put_metric_data.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class PutMetricData < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/cloud_watch/set_alarm_state.rb b/lib/fog/aws/parsers/cloud_watch/set_alarm_state.rb new file mode 100644 index 000000000..ca308ec4b --- /dev/null +++ b/lib/fog/aws/parsers/cloud_watch/set_alarm_state.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module CloudWatch + class SetAlarmState < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/allocate_address.rb b/lib/fog/aws/parsers/compute/allocate_address.rb new file mode 100644 index 000000000..0216f1817 --- /dev/null +++ b/lib/fog/aws/parsers/compute/allocate_address.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class AllocateAddress < Fog::Parsers::Base + def end_element(name) + case name + when 'publicIp', 'requestId', 'domain', 'allocationId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/assign_private_ip_addresses.rb b/lib/fog/aws/parsers/compute/assign_private_ip_addresses.rb new file mode 100644 index 000000000..122f8dde0 --- /dev/null +++ b/lib/fog/aws/parsers/compute/assign_private_ip_addresses.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class AssignPrivateIpAddresses < Fog::Parsers::Base + def end_element(name) + case name + when 'requestId' + @response[name] = value + when 'return' + if value == 'true' + @response[name] = true + else + @response[name] = false + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/associate_address.rb b/lib/fog/aws/parsers/compute/associate_address.rb new file mode 100644 index 000000000..236a281ad --- /dev/null +++ b/lib/fog/aws/parsers/compute/associate_address.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class AssociateAddress < Fog::Parsers::Base + def end_element(name) + case name + when 'requestId', 'associationId' + @response[name] = value + when 'return' + if value == 'true' + @response[name] = true + else + @response[name] = false + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/associate_route_table.rb b/lib/fog/aws/parsers/compute/associate_route_table.rb new file mode 100755 index 000000000..5a2143f04 --- /dev/null +++ b/lib/fog/aws/parsers/compute/associate_route_table.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class AssociateRouteTable < Fog::Parsers::Base + def end_element(name) + case name + when 'requestId', 'associationId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/attach_network_interface.rb b/lib/fog/aws/parsers/compute/attach_network_interface.rb new file mode 100644 index 000000000..8dee1f70e --- /dev/null +++ b/lib/fog/aws/parsers/compute/attach_network_interface.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class AttachNetworkInterface < Fog::Parsers::Base + def end_element(name) + case name + when 'requestId', 'attachmentId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/attach_volume.rb b/lib/fog/aws/parsers/compute/attach_volume.rb new file mode 100644 index 000000000..dcb5d690c --- /dev/null +++ b/lib/fog/aws/parsers/compute/attach_volume.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module Compute + module AWS + class AttachVolume < Fog::Parsers::Base + def end_element(name) + case name + when 'attachTime' + @response[name] = Time.parse(value) + when 'device', 'instanceId', 'requestId', 'status', 'volumeId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/basic.rb b/lib/fog/aws/parsers/compute/basic.rb new file mode 100644 index 000000000..d8e638e28 --- /dev/null +++ b/lib/fog/aws/parsers/compute/basic.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class Basic < Fog::Parsers::Base + def end_element(name) + case name + when 'requestId' + @response[name] = value + when 'return' + if value == 'true' + @response[name] = true + else + @response[name] = false + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/cancel_spot_instance_requests.rb b/lib/fog/aws/parsers/compute/cancel_spot_instance_requests.rb new file mode 100644 index 000000000..f03e7300c --- /dev/null +++ b/lib/fog/aws/parsers/compute/cancel_spot_instance_requests.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class CancelSpotInstanceRequests < Fog::Parsers::Base + def reset + @spot_instance_request = {} + @response = { 'spotInstanceRequestSet' => [] } + end + + def end_element(name) + case name + when 'item' + @response['spotInstanceRequestSet'] << @spot_instance_request + @spot_instance_request = {} + when 'requestId' + @response[name] = value + when 'spotInstanceRequestId', 'state' + @spot_instance_request[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/copy_image.rb b/lib/fog/aws/parsers/compute/copy_image.rb new file mode 100644 index 000000000..96e21ea91 --- /dev/null +++ b/lib/fog/aws/parsers/compute/copy_image.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module Compute + module AWS + class CopyImage < Fog::Parsers::Base + def end_element(name) + case name + when 'imageId' + @response[name] = value + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/copy_snapshot.rb b/lib/fog/aws/parsers/compute/copy_snapshot.rb new file mode 100644 index 000000000..f57be2d94 --- /dev/null +++ b/lib/fog/aws/parsers/compute/copy_snapshot.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module Compute + module AWS + class CopySnapshot < Fog::Parsers::Base + def end_element(name) + case name + when 'snapshotId' + @response[name] = value + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_dhcp_options.rb b/lib/fog/aws/parsers/compute/create_dhcp_options.rb new file mode 100644 index 000000000..4dadd93e3 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_dhcp_options.rb @@ -0,0 +1,73 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateDhcpOptions < Fog::Parsers::Base + def reset + @dhcp_options = { 'dhcpConfigurationSet' => {}, 'tagSet' => {} } + @response = { 'dhcpOptionsSet' => [] } + @tag = {} + @value_set = [] + @dhcp_configuration = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + when 'dhcpConfigurationSet' + @in_dhcp_configuration_set = true + when 'valueSet' + @in_value_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @dhcp_options['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + elsif @in_dhcp_configuration_set + case name + when 'item' + unless @in_value_set + @dhcp_options['dhcpConfigurationSet'][@dhcp_configuration['key']] = @value_set + @value_set=[] + @dhcp_configuration = {} + end + when 'key', 'value' + if !@in_value_set + @dhcp_configuration[name] = value + else + @value_set << value + end + when 'valueSet' + @in_value_set = false + when 'dhcpConfigurationSet' + @in_dhcp_configuration_set = false + end + else + case name + when 'dhcpOptionsId' + @dhcp_options[name] = value + when 'dhcpOptions' + @response['dhcpOptionsSet'] << @dhcp_options + @dhcp_options = { 'tagSet' => {} } + @dhcp_options = { 'dhcpOptionsSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_image.rb b/lib/fog/aws/parsers/compute/create_image.rb new file mode 100644 index 000000000..880f1bc29 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_image.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateImage < Fog::Parsers::Base + def end_element(name) + case name + when 'instanceId', 'requestId', 'name', 'description', 'noReboot', 'imageId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_internet_gateway.rb b/lib/fog/aws/parsers/compute/create_internet_gateway.rb new file mode 100644 index 000000000..856264a6b --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_internet_gateway.rb @@ -0,0 +1,61 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateInternetGateway < Fog::Parsers::Base + def reset + @internet_gateway = { 'attachmentSet' => {}, 'tagSet' => {} } + @response = { 'internetGatewaySet' => [] } + @tag = {} + @attachment = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + when 'attachmentSet' + @in_attachment_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @vpc['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + elsif @in_attachment_set + case name + when 'item' + @internet_gateway['attachmentSet'][@attachment['key']] = @attachment['value'] + @attachment = {} + when 'key', 'value' + @attachment[name] = value + when 'attachmentSet' + @in_attachment_set = false + end + else + case name + when 'internetGatewayId' + @internet_gateway[name] = value + when 'internetGateway' + @response['internetGatewaySet'] << @internet_gateway + @internet_gateway = { 'tagSet' => {} } + @internet_gateway = { 'attachmentSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_key_pair.rb b/lib/fog/aws/parsers/compute/create_key_pair.rb new file mode 100644 index 000000000..678e375cc --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_key_pair.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateKeyPair < Fog::Parsers::Base + def end_element(name) + case name + when 'keyFingerprint', 'keyMaterial', 'keyName', 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_network_acl.rb b/lib/fog/aws/parsers/compute/create_network_acl.rb new file mode 100644 index 000000000..4ebfa0c10 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_network_acl.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module Compute + module AWS + require 'fog/aws/parsers/compute/network_acl_parser' + + class CreateNetworkAcl < NetworkAclParser + def reset + super + @response = { 'networkAcl' => {} } + end + + def end_element(name) + case name + when 'requestId' + @response[name] = value + when 'networkAcl' + @response['networkAcl'] = @network_acl + reset_nacl + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_network_interface.rb b/lib/fog/aws/parsers/compute/create_network_interface.rb new file mode 100644 index 000000000..d965b7630 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_network_interface.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module Compute + module AWS + require 'fog/aws/parsers/compute/network_interface_parser' + + class CreateNetworkInterface < NetworkInterfaceParser + def reset + super + @response = { 'networkInterface' => {} } + end + + def end_element(name) + case name + when 'requestId' + @response[name] = value + when 'networkInterface' + @response['networkInterface'] = @nic + reset_nic + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_route_table.rb b/lib/fog/aws/parsers/compute/create_route_table.rb new file mode 100755 index 000000000..19e42ba44 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_route_table.rb @@ -0,0 +1,71 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateRouteTable < Fog::Parsers::Base + def reset + @in_route_set = false + @in_association_set = false + @route = {} + @association = {} + @route_table = { 'routeSet' => [], 'tagSet' => {}, 'associationSet' => [] } + @response = { 'routeTable' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + when 'routeSet' + @in_route_set = true + when 'associationSet' + @in_association_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @route_table['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'tagSet' + @in_tag_set = false + end + elsif @in_route_set + case name + when 'routeSet' + @in_route_set = false + when 'destinationCidrBlock', 'gatewayId', 'state' + @route[name] = value + when 'item' + @route_table['routeSet'] << @route + @route = {} + end + elsif @in_association_set + case name + when 'routeTableAssociationId', 'routeTableId', 'main' + @association[name] = value + when 'associationSet' + @route_table['associationSet'] << @association + @in_association_set = false + end + else + case name + when 'routeTableId', 'vpcId' + @route_table[name] = value + when 'routeTable' + @response['routeTable'] << @route_table + @route_table = { 'routeSet' => {}, 'tagSet' => {}, 'associationSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_security_group.rb b/lib/fog/aws/parsers/compute/create_security_group.rb new file mode 100644 index 000000000..c64dd8d06 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_security_group.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateSecurityGroup < Fog::Parsers::Base + def end_element(name) + case name + when 'return' + if value == 'true' + @response[name] = true + else + @response[name] = false + end + when 'requestId', 'groupId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_snapshot.rb b/lib/fog/aws/parsers/compute/create_snapshot.rb new file mode 100644 index 000000000..4535b2343 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_snapshot.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateSnapshot < Fog::Parsers::Base + def end_element(name) + case name + when 'description', 'ownerId', 'progress', 'snapshotId', 'status', 'volumeId' + @response[name] = value + when 'requestId' + @response[name] = value + when 'startTime' + @response[name] = Time.parse(value) + when 'volumeSize' + @response[name] = value.to_i + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_subnet.rb b/lib/fog/aws/parsers/compute/create_subnet.rb new file mode 100644 index 000000000..226ba0612 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_subnet.rb @@ -0,0 +1,46 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateSubnet < Fog::Parsers::Base + def reset + @subnet = { 'tagSet' => {} } + @response = { 'subnet' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @subnet['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'subnetId', 'state', 'vpcId', 'cidrBlock', 'availableIpAddressCount', 'availabilityZone' + @subnet[name] = value + when 'subnet' + @response['subnet'] = @subnet + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_volume.rb b/lib/fog/aws/parsers/compute/create_volume.rb new file mode 100644 index 000000000..f1d8aea2c --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_volume.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateVolume < Fog::Parsers::Base + def end_element(name) + case name + when 'availabilityZone', 'requestId', 'snapshotId', 'status', 'volumeId', 'volumeType' + @response[name] = value + when 'createTime' + @response[name] = Time.parse(value) + when 'size', 'iops' + @response[name] = value.to_i + when 'encrypted' + @response[name] = (value == 'true') + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/create_vpc.rb b/lib/fog/aws/parsers/compute/create_vpc.rb new file mode 100644 index 000000000..e20e5a336 --- /dev/null +++ b/lib/fog/aws/parsers/compute/create_vpc.rb @@ -0,0 +1,47 @@ +module Fog + module Parsers + module Compute + module AWS + class CreateVpc < Fog::Parsers::Base + def reset + @vpc = { 'tagSet' => {} } + @response = { 'vpcSet' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @vpc['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'vpcId', 'state', 'cidrBlock', 'dhcpOptionsId' + @vpc[name] = value + when 'vpc' + @response['vpcSet'] << @vpc + @vpc = { 'tagSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/deregister_image.rb b/lib/fog/aws/parsers/compute/deregister_image.rb new file mode 100644 index 000000000..176f3eb12 --- /dev/null +++ b/lib/fog/aws/parsers/compute/deregister_image.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class DeregisterImage < Fog::Parsers::Base + def end_element(name) + case name + when 'return', 'requestId', 'imageId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_account_attributes.rb b/lib/fog/aws/parsers/compute/describe_account_attributes.rb new file mode 100644 index 000000000..29ca5ec17 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_account_attributes.rb @@ -0,0 +1,41 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeAccountAttributes < Fog::Parsers::Base + def reset + @attribute = { 'values' => []} + @account_attributes = [] + @response = { 'accountAttributeSet' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'attributeValueSet' + @in_attribute_value_set = true + end + end + + def end_element(name) + case name + when 'attributeName' + @attribute[name] = value + when 'attributeValue' + @attribute['values'] << value + when['requestId'] + @response[name] = value + when 'item' + @response['accountAttributeSet'] << @attribute + @attribute = { 'values' => []} unless @in_attribute_value_set + when 'attributeValueSet' + @in_attribute_value_set = false + else + end + @response['accountAttributeSet'].uniq! + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_addresses.rb b/lib/fog/aws/parsers/compute/describe_addresses.rb new file mode 100644 index 000000000..9b9515e87 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_addresses.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeAddresses < Fog::Parsers::Base + def reset + @address = {} + @response = { 'addressesSet' => [] } + end + + def end_element(name) + case name + when 'instanceId', 'publicIp', 'domain', 'allocationId', 'associationId', 'networkInterfaceId', 'networkInterfaceOwnerId' + @address[name] = value + when 'item' + @response['addressesSet'] << @address + @address = {} + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_availability_zones.rb b/lib/fog/aws/parsers/compute/describe_availability_zones.rb new file mode 100644 index 000000000..16484e870 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_availability_zones.rb @@ -0,0 +1,40 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeAvailabilityZones < Fog::Parsers::Base + def start_element(name, attrs = []) + case name + when 'messageSet' + @in_message_set = true + end + super + end + + def reset + @availability_zone = { 'messageSet' => [] } + @response = { 'availabilityZoneInfo' => [] } + end + + def end_element(name) + case name + when 'item' + unless @in_message_set + @response['availabilityZoneInfo'] << @availability_zone + @availability_zone = { 'messageSet' => [] } + end + when 'message' + @availability_zone['messageSet'] << value + when 'regionName', 'zoneName', 'zoneState' + @availability_zone[name] = value + when 'requestId' + @response[name] = value + when 'messageSet' + @in_message_set = false + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_dhcp_options.rb b/lib/fog/aws/parsers/compute/describe_dhcp_options.rb new file mode 100644 index 000000000..061c04fb3 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_dhcp_options.rb @@ -0,0 +1,72 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeDhcpOptions < Fog::Parsers::Base + def reset + @dhcp_options = { 'dhcpConfigurationSet' => {}, 'tagSet' => {} } + @response = { 'dhcpOptionsSet' => [] } + @tag = {} + @value_set = [] + @dhcp_configuration = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + when 'dhcpConfigurationSet' + @in_dhcp_configuration_set = true + when 'valueSet' + @in_value_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @dhcp_options['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + elsif @in_dhcp_configuration_set + case name + when 'item' + unless @in_value_set + @dhcp_options['dhcpConfigurationSet'][@dhcp_configuration['key']] = @value_set + @value_set=[] + @dhcp_configuration = {} + end + when 'key', 'value' + if !@in_value_set + @dhcp_configuration[name] = value + else + @value_set << value + end + when 'valueSet' + @in_value_set = false + when 'dhcpConfigurationSet' + @in_dhcp_configuration_set = false + end + else + case name + when 'dhcpOptionsId' + @dhcp_options[name] = value + when 'item' + @response['dhcpOptionsSet'] << @dhcp_options + @dhcp_options = { 'dhcpConfigurationSet' => {}, 'tagSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_images.rb b/lib/fog/aws/parsers/compute/describe_images.rb new file mode 100644 index 000000000..bcd9fd81f --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_images.rb @@ -0,0 +1,89 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeImages < Fog::Parsers::Base + def reset + @block_device_mapping = {} + @image = { 'blockDeviceMapping' => [], 'productCodes' => [], 'stateReason' => {}, 'tagSet' => {} } + @response = { 'imagesSet' => [] } + @state_reason = {} + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'blockDeviceMapping' + @in_block_device_mapping = true + when 'productCodes' + @in_product_codes = true + when 'stateReason' + @in_state_reason = true + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_block_device_mapping + case name + when 'blockDeviceMapping' + @in_block_device_mapping = false + when 'deviceName', 'virtualName', 'snapshotId', 'deleteOnTermination' + @block_device_mapping[name] = value + when 'volumeSize' + @block_device_mapping[name] = value.to_i + when 'item' + @image['blockDeviceMapping'] << @block_device_mapping + @block_device_mapping = {} + end + elsif @in_product_codes + case name + when 'productCode' + @image['productCodes'] << value + when 'productCodes' + @in_product_codes = false + end + elsif @in_tag_set + case name + when 'item' + @image['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + elsif @in_state_reason + case name + when 'code', 'message' + @state_reason[name] = value + when 'stateReason' + @image['stateReason'] = @state_reason + @state_reason = {} + @in_state_reason = false + end + else + case name + when 'architecture', 'description', 'hypervisor', 'imageId', 'imageLocation', 'imageOwnerAlias', 'imageOwnerId', 'imageState', 'imageType', 'kernelId', 'name', 'platform', 'ramdiskId', 'rootDeviceType','rootDeviceName','virtualizationType' + @image[name] = value + when 'isPublic' + if value == 'true' + @image[name] = true + else + @image[name] = false + end + when 'item' + @response['imagesSet'] << @image + @image = { 'blockDeviceMapping' => [], 'productCodes' => [], 'stateReason' => {}, 'tagSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_instance_status.rb b/lib/fog/aws/parsers/compute/describe_instance_status.rb new file mode 100644 index 000000000..502d6a126 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_instance_status.rb @@ -0,0 +1,73 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeInstanceStatus < Fog::Parsers::Base + def new_instance! + @instance = { 'instanceState' => {}, 'systemStatus' => { 'details' => [] }, 'instanceStatus' => { 'details' => [] }, 'eventsSet' => [] } + end + + def new_item! + @item = {} + end + + def reset + @response = { 'instanceStatusSet' => [] } + @inside = nil + end + + def start_element(name, attrs=[]) + super + case name + when 'item' + if @inside + new_item! + else + new_instance! + end + when 'systemStatus' + @inside = :systemStatus + when 'instanceState' + @inside = :instanceState + when 'instanceStatus' + @inside = :instanceStatus + when 'eventsSet' + @inside = :eventsSet + end + end + + def end_element(name) + case name + #Simple closers + when 'instanceId', 'availabilityZone' + @instance[name] = value + when 'nextToken', 'requestId' + @response[name] = value + when 'systemStatus', 'instanceState', 'instanceStatus', 'eventsSet' + @inside = nil + when 'item' + case @inside + when :eventsSet + @instance['eventsSet'] << @item + when :systemStatus, :instanceStatus + @instance[@inside.to_s]['details'] << @item + when nil + @response['instanceStatusSet'] << @instance + end + @item = nil + when 'code' + case @inside + when :eventsSet + @item[name] = value + when :instanceState + @instance[@inside.to_s][name] = value.to_i + end + when 'description', 'notBefore', 'notAfter', 'name', 'status' + @item.nil? ? (@instance[@inside.to_s][name] = value) : (@item[name] = value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_instances.rb b/lib/fog/aws/parsers/compute/describe_instances.rb new file mode 100644 index 000000000..8d8eb9d4b --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_instances.rb @@ -0,0 +1,122 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeInstances < Fog::Parsers::Base + def reset + @block_device_mapping = {} + @network_interface = {} + @context = [] + @contexts = ['blockDevices', 'blockDeviceMapping', 'groupSet', 'iamInstanceProfile', 'instancesSet', 'instanceState', 'networkInterfaceSet', 'placement', 'productCodes', 'stateReason', 'tagSet'] + @instance = { 'blockDeviceMapping' => [], 'networkInterfaces' => [], 'iamInstanceProfile' => {}, 'instanceState' => {}, 'monitoring' => {}, 'placement' => {}, 'productCodes' => [], 'stateReason' => {}, 'tagSet' => {} } + @reservation = { 'groupIds' => [], 'groupSet' => [], 'instancesSet' => [] } + @response = { 'reservationSet' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + if @contexts.include?(name) + @context.push(name) + end + end + + def end_element(name) + case name + when 'amiLaunchIndex' + @instance[name] = value.to_i + when 'arn' + @instance[@context.last][name] = value + when 'availabilityZone', 'tenancy' + @instance['placement'][name] = value + when 'architecture', 'clientToken', 'dnsName', 'hypervisor', 'imageId', + 'instanceId', 'instanceType', 'ipAddress', 'kernelId', 'keyName', + 'instanceLifecycle', 'platform', 'privateDnsName', 'privateIpAddress', 'ramdiskId', + 'reason', 'requesterId', 'rootDeviceName', 'rootDeviceType', + 'spotInstanceRequestId', 'virtualizationType' + @instance[name] = value + when 'attachTime' + @block_device_mapping[name] = Time.parse(value) + when *@contexts + @context.pop + when 'code' + @instance[@context.last][name] = @context.last == 'stateReason' ? value : value.to_i + when 'message' + @instance[@context.last][name] = value + when 'deleteOnTermination' + @block_device_mapping[name] = (value == 'true') + when 'deviceName', 'status', 'volumeId' + @block_device_mapping[name] = value + when 'subnetId', 'vpcId', 'ownerId', 'networkInterfaceId', 'attachmentId' + @network_interface[name] = value + @instance[name] = value + when 'groupId', 'groupName' + case @context.last + when 'groupSet' + (name == 'groupName') ? current_key = 'groupSet' : current_key = 'groupIds' + case @context[-2] + when 'instancesSet' + @reservation[current_key] << value + when 'networkInterfaceSet' + @network_interface[current_key] ||= [] + @network_interface[current_key] << value + end + when 'placement' + @instance['placement'][name] = value + end + when 'id' + @instance[@context.last][name] = value + when 'item' + case @context.last + when 'blockDeviceMapping' + @instance['blockDeviceMapping'] << @block_device_mapping + @block_device_mapping = {} + when 'networkInterfaceSet' + @instance['networkInterfaces'] << @network_interface + @network_interface = {} + when 'instancesSet' + @reservation['instancesSet'] << @instance + @instance = { 'blockDeviceMapping' => [], 'networkInterfaces' => [], 'iamInstanceProfile' => {}, 'instanceState' => {}, 'monitoring' => {}, 'placement' => {}, 'productCodes' => [], 'stateReason' => {}, 'tagSet' => {} } + when 'tagSet' + @instance['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'blockDevices' + # Ignore this one (Eucalyptus specific) + when nil + @response['reservationSet'] << @reservation + @reservation = { 'groupIds' => [], 'groupSet' => [], 'instancesSet' => [] } + end + when 'key', 'value' + @tag[name] = value + when 'launchTime' + @instance[name] = Time.parse(value) + when 'name' + @instance[@context.last][name] = value + when 'ownerId', 'reservationId' + @reservation[name] = value + when 'requestId', 'nextToken' + @response[name] = value + when 'productCode' + @instance['productCodes'] << value + when 'state' + @instance['monitoring'][name] = (value == 'enabled') + when 'ebsOptimized' + @instance['ebsOptimized'] = (value == 'true') + when 'sourceDestCheck' + if value == 'true' + @instance[name] = true + else + @instance[name] = false + end + # Eucalyptus passes status in schema non conforming way + when 'stateCode' + @instance['instanceState']['code'] = value + when 'stateName' + @instance['instanceState']['name'] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_internet_gateways.rb b/lib/fog/aws/parsers/compute/describe_internet_gateways.rb new file mode 100644 index 000000000..093b71359 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_internet_gateways.rb @@ -0,0 +1,60 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeInternetGateways < Fog::Parsers::Base + def reset + @internet_gateway = { 'attachmentSet' => {}, 'tagSet' => {} } + @response = { 'internetGatewaySet' => [] } + @tag = {} + @attachment = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + when 'attachmentSet' + @in_attachment_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @internet_gateway['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + elsif @in_attachment_set + case name + when 'item' + @internet_gateway['attachmentSet']=@attachment + @attachment = {} + when 'vpcId', 'state' + @attachment[name] = value + when 'attachmentSet' + @in_attachment_set = false + end + else + case name + when 'internetGatewayId' + @internet_gateway[name] = value + when 'item' + @response['internetGatewaySet'] << @internet_gateway + @internet_gateway = { 'attachmentSet' => {}, 'tagSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_key_pairs.rb b/lib/fog/aws/parsers/compute/describe_key_pairs.rb new file mode 100644 index 000000000..21be7ab20 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_key_pairs.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeKeyPairs < Fog::Parsers::Base + def reset + @key = {} + @response = { 'keySet' => [] } + end + + def end_element(name) + case name + when 'item' + @response['keySet'] << @key + @key = {} + when 'keyFingerprint', 'keyName' + @key[name] = value + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_network_acls.rb b/lib/fog/aws/parsers/compute/describe_network_acls.rb new file mode 100644 index 000000000..c02061468 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_network_acls.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module Compute + module AWS + require 'fog/aws/parsers/compute/network_acl_parser' + + class DescribeNetworkAcls < NetworkAclParser + def reset + super + @response = { 'networkAclSet' => [] } + @item_level = 0 + end + + def start_element(name, attrs = []) + super + case name + when 'item' + @item_level += 1 + end + end + + def end_element(name) + case name + when 'requestId' + @response[name] = value + when 'item' + @item_level -= 1 + if @item_level == 0 + @response['networkAclSet'] << @network_acl + reset_nacl + else + super + end + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_network_interface_attribute.rb b/lib/fog/aws/parsers/compute/describe_network_interface_attribute.rb new file mode 100644 index 000000000..d42193ab5 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_network_interface_attribute.rb @@ -0,0 +1,77 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeNetworkInterfaceAttribute < NetworkInterfaceParser + def reset + @response = { } + @in_description = false + @in_group_set = false + @in_source_dest_check = false + @in_attachment = false + end + + def start_element(name, attrs = []) + super + case name + when 'description' + @in_description = true + when 'groupSet' + @in_group_set = true + @group = {} + unless @response.key?('groupSet') + @response['groupSet'] = {} + end + when 'sourceDestCheck' + @in_source_dest_check = true + when 'attachment' + @in_attachment = true + @attachment = {} + end + end + + def end_element(name) + if @in_description + case name + when 'value' + @response['description'] = value + when 'description' + @in_description = false + end + elsif @in_group_set + case name + when 'item' + @response['groupSet'][@group['groupId']] = @group['groupName'] + @group = {} + when 'groupId', 'groupName' + @group[name] = value + when 'groupSet' + @in_group_set = false + end + elsif @in_source_dest_check + case name + when 'value' + @response['sourceDestCheck'] = (value == 'true') + when 'sourceDestCheck' + @in_source_dest_check = false + end + elsif @in_attachment + case name + when 'attachmentId', 'instanceId', 'instanceOwnerId', 'deviceIndex', 'status', 'attachTime', 'deleteOnTermination' + @attachment[name] = value + when 'attachment' + @response['attachment'] = @attachment + @in_attachment = false + end + else + case name + when 'requestId', 'networkInterfaceId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_network_interfaces.rb b/lib/fog/aws/parsers/compute/describe_network_interfaces.rb new file mode 100644 index 000000000..28d4db18b --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_network_interfaces.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module Compute + module AWS + require 'fog/aws/parsers/compute/network_interface_parser' + + class DescribeNetworkInterfaces < NetworkInterfaceParser + def reset + super + @response = { 'networkInterfaceSet' => [] } + @item_level = 0 + end + + def start_element(name, attrs = []) + super + case name + when 'item' + @item_level += 1 + end + end + + def end_element(name) + case name + when 'requestId' + @response[name] = value + when 'item' + @item_level -= 1 + if @item_level == 0 + @response['networkInterfaceSet'] << @nic + reset_nic + else + super + end + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_placement_groups.rb b/lib/fog/aws/parsers/compute/describe_placement_groups.rb new file mode 100644 index 000000000..7901081a8 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_placement_groups.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribePlacementGroups < Fog::Parsers::Base + def reset + @placement_group = {} + @response = { 'placementGroupSet' => [] } + end + + def end_element(name) + case name + when 'item' + @response['placementGroupSet'] << @placement_group + @placement_group = {} + when 'groupName', 'state', 'strategy' + @placement_group[name] = value + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_regions.rb b/lib/fog/aws/parsers/compute/describe_regions.rb new file mode 100644 index 000000000..f0147269d --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_regions.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeRegions < Fog::Parsers::Base + def reset + @region = {} + @response = { 'regionInfo' => [] } + end + + def end_element(name) + case name + when 'item' + @response['regionInfo'] << @region + @region = {} + when 'regionEndpoint', 'regionName' + @region[name] = value + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_reserved_instances.rb b/lib/fog/aws/parsers/compute/describe_reserved_instances.rb new file mode 100644 index 000000000..3546abf66 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_reserved_instances.rb @@ -0,0 +1,58 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeReservedInstances < Fog::Parsers::Base + def get_default_item + {'tagSet' => {}, 'recurringCharges' => {}} + end + + def reset + @context = [] + # Note: should also be handled as a set, but do not want to disrupt anyone relying on + # it currently being flatted + @contexts = ['reservedInstancesSet', 'tagSet'] + @reserved_instance = get_default_item + @response = { 'reservedInstancesSet' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + if @contexts.include?(name) + @context.push(name) + end + end + + def end_element(name) + case name + when 'availabilityZone', 'instanceType', 'productDescription', 'reservedInstancesId', 'state', 'offeringType' + @reserved_instance[name] = value + when 'duration', 'instanceCount' + @reserved_instance[name] = value.to_i + when 'fixedPrice', 'amount', 'usagePrice' + @reserved_instance[name] = value.to_f + when *@contexts + @context.pop + when 'item' + case @context.last + when 'reservedInstancesSet' + @response['reservedInstancesSet'] << @reserved_instance + @reserved_instance = get_default_item + when 'tagSet' + @reserved_instance['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + end + when 'key', 'value' + @tag[name] = value + when 'requestId' + @response[name] = value + when 'start','end' + @reserved_instance[name] = Time.parse(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_reserved_instances_offerings.rb b/lib/fog/aws/parsers/compute/describe_reserved_instances_offerings.rb new file mode 100644 index 000000000..3f9e6c8ff --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_reserved_instances_offerings.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeReservedInstancesOfferings < Fog::Parsers::Base + def reset + @reserved_instances_offering = {} + @response = { 'reservedInstancesOfferingsSet' => [] } + end + + def end_element(name) + case name + when 'availabilityZone', 'currencyCode', 'instanceType', 'offeringType', 'instanceTenancy', 'productDescription', 'reservedInstancesOfferingId' + @reserved_instances_offering[name] = value + when 'duration' + @reserved_instances_offering[name] = value.to_i + when 'fixedPrice', 'usagePrice' + @reserved_instances_offering[name] = value.to_f + when 'item' + @response['reservedInstancesOfferingsSet'] << @reserved_instances_offering unless @reserved_instances_offering.empty? + @reserved_instances_offering = {} + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_route_tables.rb b/lib/fog/aws/parsers/compute/describe_route_tables.rb new file mode 100755 index 000000000..924a51f1f --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_route_tables.rb @@ -0,0 +1,81 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeRouteTables < Fog::Parsers::Base + def reset + @association = { 'routeTableAssociationId' => nil, 'routeTableId' => nil, 'subnetId' => nil, 'main' => false } + @in_association_set = false + @in_route_set = false + @route = { 'destinationCidrBlock' => nil, 'gatewayId' => nil, 'instanceId' => nil, 'instanceOwnerId' => nil, 'networkInterfaceId' => nil, 'state' => nil, 'origin' => nil } + @response = { 'routeTableSet' => [] } + @tag = {} + @route_table = { 'associationSet' => [], 'tagSet' => {}, 'routeSet' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'associationSet' + @in_association_set = true + when 'tagSet' + @in_tag_set = true + when 'routeSet' + @in_route_set = true + end + end + + def end_element(name) + if @in_association_set + case name + when 'associationSet' + @in_association_set = false + when 'routeTableAssociationId', 'routeTableId', 'subnetId' + @association[name] = value + when 'main' + if value == 'true' + @association[name] = true + else + @association[name] = false + end + when 'item' + @route_table['associationSet'] << @association + @association = { 'routeTableAssociationId' => nil, 'routeTableId' => nil, 'subnetId' => nil, 'main' => false } + end + elsif @in_tag_set + case name + when 'key', 'value' + @tag[name] = value + when 'item' + @route_table['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'tagSet' + @in_tag_set = false + end + elsif @in_route_set + case name + when 'destinationCidrBlock', 'gatewayId', 'instanceId', 'instanceOwnerId', 'networkInterfaceId', 'state', 'origin' + @route[name] = value + when 'item' + @route_table['routeSet'] << @route + @route = { 'destinationCidrBlock' => nil, 'gatewayId' => nil, 'instanceId' => nil, 'instanceOwnerId' => nil, 'networkInterfaceId' => nil, 'state' => nil, 'origin' => nil } + when 'routeSet' + @in_route_set = false + end + else + case name + when 'routeTableId', 'vpcId' + @route_table[name] = value + when 'item' + @response['routeTableSet'] << @route_table + @route_table = { 'associationSet' => [], 'tagSet' => {}, 'routeSet' => [] } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_security_groups.rb b/lib/fog/aws/parsers/compute/describe_security_groups.rb new file mode 100644 index 000000000..c3562d103 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_security_groups.rb @@ -0,0 +1,111 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeSecurityGroups < Fog::Parsers::Base + def reset + @group = {} + @ip_permission = { 'groups' => [], 'ipRanges' => []} + @ip_permission_egress = { 'groups' => [], 'ipRanges' => []} + @ip_range = {} + @security_group = { 'ipPermissions' => [], 'ipPermissionsEgress' => [], 'tagSet' => {} } + @response = { 'securityGroupInfo' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'groups' + @in_groups = true + when 'ipPermissions' + @in_ip_permissions = true + when 'ipPermissionsEgress' + @in_ip_permissions_egress = true + when 'ipRanges' + @in_ip_ranges = true + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @security_group['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'cidrIp' + @ip_range[name] = value + when 'fromPort', 'toPort' + if @in_ip_permissions_egress + @ip_permission_egress[name] = value.to_i + else + @ip_permission[name] = value.to_i + end + when 'groups' + @in_groups = false + when 'groupDescription', 'ownerId', 'vpcId' + @security_group[name] = value + when 'groupId','groupName' + if @in_groups + @group[name] = value + else + @security_group[name] = value + end + when 'ipPermissions' + @in_ip_permissions = false + when 'ipPermissionsEgress' + @in_ip_permissions_egress = false + when 'ipProtocol' + if @in_ip_permissions_egress + @ip_permission_egress[name] = value + else + @ip_permission[name] = value + end + when 'ipRanges' + @in_ip_ranges = false + when 'item' + if @in_groups + if @in_ip_permissions_egress + @ip_permission_egress['groups'] << @group + else + @ip_permission['groups'] << @group + end + @group = {} + elsif @in_ip_ranges + if @in_ip_permissions_egress + @ip_permission_egress['ipRanges'] << @ip_range + else + @ip_permission['ipRanges'] << @ip_range + end + @ip_range = {} + elsif @in_ip_permissions + @security_group['ipPermissions'] << @ip_permission + @ip_permission = { 'groups' => [], 'ipRanges' => []} + elsif @in_ip_permissions_egress + @security_group['ipPermissionsEgress'] << @ip_permission_egress + @ip_permission_egress = { 'groups' => [], 'ipRanges' => []} + else + @response['securityGroupInfo'] << @security_group + @security_group = { 'ipPermissions' => [], 'ipPermissionsEgress' => [], 'tagSet' => {} } + end + when 'requestId' + @response[name] = value + when 'userId' + @group[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_snapshots.rb b/lib/fog/aws/parsers/compute/describe_snapshots.rb new file mode 100644 index 000000000..7057d59dd --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_snapshots.rb @@ -0,0 +1,52 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeSnapshots < Fog::Parsers::Base + def reset + @response = { 'snapshotSet' => [] } + @snapshot = { 'tagSet' => {} } + @tag = {} + end + + def start_element(name, attrs = []) + super + if name == 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @snapshot['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'item' + @response['snapshotSet'] << @snapshot + @snapshot = { 'tagSet' => {} } + when 'description', 'ownerId', 'progress', 'snapshotId', 'status', 'volumeId' + @snapshot[name] ||= value + when 'requestId' + @response[name] = value + when 'startTime' + @snapshot[name] = Time.parse(value) + when 'volumeSize' + @snapshot[name] = value.to_i + when 'encrypted' + @snapshot[name] = (value == 'true') + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_spot_price_history.rb b/lib/fog/aws/parsers/compute/describe_spot_price_history.rb new file mode 100644 index 000000000..53ab50d74 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_spot_price_history.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeSpotPriceHistory < Fog::Parsers::Base + def reset + @spot_price = {} + @response = { 'spotPriceHistorySet' => [] } + end + + def end_element(name) + case name + when 'availabilityZone', 'instanceType', 'productDescription' + @spot_price[name] = value + when 'item' + @response['spotPriceHistorySet'] << @spot_price + @spot_price = {} + when 'requestId' + @response[name] = value + when 'spotPrice' + @spot_price[name] = value.to_f + when 'timestamp' + @spot_price[name] = Time.parse(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_subnets.rb b/lib/fog/aws/parsers/compute/describe_subnets.rb new file mode 100644 index 000000000..4447aa63b --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_subnets.rb @@ -0,0 +1,49 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeSubnets < Fog::Parsers::Base + def reset + @subnet = { 'tagSet' => {} } + @response = { 'subnetSet' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @subnet['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'subnetId', 'state', 'vpcId', 'cidrBlock', 'availableIpAddressCount', 'availabilityZone' + @subnet[name] = value + when 'mapPublicIpOnLaunch' + @subnet[name] = value == 'true' ? true : false + when 'item' + @response['subnetSet'] << @subnet + @subnet = { 'tagSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_tags.rb b/lib/fog/aws/parsers/compute/describe_tags.rb new file mode 100644 index 000000000..7859f88c5 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_tags.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeTags < Fog::Parsers::Base + def reset + @tag = {} + @response = { 'tagSet' => [] } + end + + def end_element(name) + case name + when 'resourceId', 'resourceType', 'key', 'value' + @tag[name] = value + when 'item' + @response['tagSet'] << @tag + @tag = {} + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_volume_status.rb b/lib/fog/aws/parsers/compute/describe_volume_status.rb new file mode 100644 index 000000000..9a37fe680 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_volume_status.rb @@ -0,0 +1,87 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeVolumeStatus < Fog::Parsers::Base + def reset + @action_set = {} + @detail = {} + @event_set = {} + @volume_status = { 'details' => [] } + @volume = { 'actionsSet' => [], 'eventsSet' => [] } + @response = { 'volumeStatusSet' => [] } + end + + def start_element(name, attrs=[]) + super + case name + when 'actionsSet' + @in_actions_set = true + when 'details' + @in_details = true + when 'eventsSet' + @in_events_set = true + when 'volumeStatus' + @in_volume_status = true + end + end + + def end_element(name) + if @in_actions_set + case name + when 'actionsSet' + @in_actions_set = false + when 'code', 'eventId', 'eventType', 'description' + @action_set[name] = value.strip + when 'item' + @volume['actionsSet'] << @action_set + @action_set = {} + end + elsif @in_details + case name + when 'details' + @in_details = false + when 'name', 'status' + @detail[name] = value + when 'item' + @volume_status['details'] << @detail + @detail = {} + end + elsif @in_events_set + case name + when 'eventsSet' + @in_events_set = false + when 'code', 'eventId', 'eventType', 'description' + @event_set[name] = value.strip + when 'notAfter', 'notBefore' + @event_set[name] = Time.parse(value) + when 'item' + @volume['eventsSet'] << @event_set + @event_set = {} + end + elsif @in_volume_status + case name + when 'volumeStatus' + @volume['volumeStatus'] = @volume_status + @volume_status = { 'details' => [] } + @in_volume_status = false + when 'status' + @volume_status[name] = value + end + else + case name + when 'volumeId', 'availabilityZone' + @volume[name] = value + when 'nextToken', 'requestId' + @response[name] = value + when 'item' + @response['volumeStatusSet'] << @volume + @volume = { 'actionsSet' => [], 'eventsSet' => [] } + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_volumes.rb b/lib/fog/aws/parsers/compute/describe_volumes.rb new file mode 100644 index 000000000..266e75987 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_volumes.rb @@ -0,0 +1,71 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeVolumes < Fog::Parsers::Base + def reset + @attachment = {} + @in_attachment_set = false + @response = { 'volumeSet' => [] } + @tag = {} + @volume = { 'attachmentSet' => [], 'tagSet' => {} } + end + + def start_element(name, attrs = []) + super + case name + when 'attachmentSet' + @in_attachment_set = true + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_attachment_set + case name + when 'attachmentSet' + @in_attachment_set = false + when 'attachTime' + @attachment[name] = Time.parse(value) + when 'deleteOnTermination' + @attachment[name] = value == 'true' + when 'device', 'instanceId', 'status', 'volumeId' + @attachment[name] = value + when 'item' + @volume['attachmentSet'] << @attachment + @attachment = {} + end + elsif @in_tag_set + case name + when 'key', 'value' + @tag[name] = value + when 'item' + @volume['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'availabilityZone', 'snapshotId', 'status', 'volumeId', 'volumeType' + @volume[name] = value + when 'createTime' + @volume[name] = Time.parse(value) + when 'item' + @response['volumeSet'] << @volume + @volume = { 'attachmentSet' => [], 'tagSet' => {} } + when 'requestId' + @response[name] = value + when 'size', 'iops' + @volume[name] = value.to_i + when 'encrypted' + @volume[name] = (value == 'true') + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_vpc_attribute.rb b/lib/fog/aws/parsers/compute/describe_vpc_attribute.rb new file mode 100644 index 000000000..7834219d0 --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_vpc_attribute.rb @@ -0,0 +1,48 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeVpcAttribute < Fog::Parsers::Base + def reset + @response = { } + @in_enable_dns_support = false + @in_enable_dns_hostnames = false + end + + def start_element(name, attrs = []) + super + case name + when 'enableDnsSupport' + @in_enable_dns_support = true + when 'enableDnsHostnames' + @in_enable_dns_hostnames = true + end + end + + def end_element(name) + if @in_enable_dns_support + case name + when 'value' + @response['enableDnsSupport'] = (value == 'true') + when 'enableDnsSupport' + @in_enable_dns_support = false + end + elsif @in_enable_dns_hostnames + case name + when 'value' + @response['enableDnsHostnames'] = (value == 'true') + when 'enableDnsHostnames' + @in_enable_dns_hostnames = false + end + else + case name + when 'requestId', 'vpcId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/describe_vpcs.rb b/lib/fog/aws/parsers/compute/describe_vpcs.rb new file mode 100644 index 000000000..3e5f4642d --- /dev/null +++ b/lib/fog/aws/parsers/compute/describe_vpcs.rb @@ -0,0 +1,47 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeVpcs < Fog::Parsers::Base + def reset + @vpc = { 'tagSet' => {} } + @response = { 'vpcSet' => [] } + @tag = {} + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @vpc['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + else + case name + when 'vpcId', 'state', 'cidrBlock', 'dhcpOptionsId', 'instanceTenancy' + @vpc[name] = value + when 'item' + @response['vpcSet'] << @vpc + @vpc = { 'tagSet' => {} } + when 'requestId' + @response[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/detach_volume.rb b/lib/fog/aws/parsers/compute/detach_volume.rb new file mode 100644 index 000000000..5def4620c --- /dev/null +++ b/lib/fog/aws/parsers/compute/detach_volume.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module Compute + module AWS + class DetachVolume < Fog::Parsers::Base + def end_element(name) + case name + when 'attachTime' + @response[name] = Time.parse(value) + when 'device', 'instanceId', 'requestId', 'status', 'volumeId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/get_console_output.rb b/lib/fog/aws/parsers/compute/get_console_output.rb new file mode 100644 index 000000000..e7533de6c --- /dev/null +++ b/lib/fog/aws/parsers/compute/get_console_output.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module Compute + module AWS + class GetConsoleOutput < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'instanceId', 'requestId' + @response[name] = value + when 'output' + @response[name] = value && Base64.decode64(value) + when 'timestamp' + @response[name] = Time.parse(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/get_password_data.rb b/lib/fog/aws/parsers/compute/get_password_data.rb new file mode 100644 index 000000000..688ba5c3e --- /dev/null +++ b/lib/fog/aws/parsers/compute/get_password_data.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module Compute + module AWS + class GetPasswordData < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'instanceId', 'requestId', 'passwordData' + @response[name] = @value + when 'timestamp' + @response[name] = Time.parse(@value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/import_key_pair.rb b/lib/fog/aws/parsers/compute/import_key_pair.rb new file mode 100644 index 000000000..9d8a68792 --- /dev/null +++ b/lib/fog/aws/parsers/compute/import_key_pair.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class ImportKeyPair < Fog::Parsers::Base + def end_element(name) + case name + when 'keyFingerprint', 'keyName', 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/modify_subnet_attribute.rb b/lib/fog/aws/parsers/compute/modify_subnet_attribute.rb new file mode 100644 index 000000000..398b16040 --- /dev/null +++ b/lib/fog/aws/parsers/compute/modify_subnet_attribute.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module Compute + module AWS + class ModifySubnetAttribute < Fog::Parsers::Base + def reset + @response = { } + end + + + def end_element(name) + case name + when 'return' + @response[name] = value == 'true' ? true : false + when 'requestId' + @response[name] = value + end + + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/monitor_unmonitor_instances.rb b/lib/fog/aws/parsers/compute/monitor_unmonitor_instances.rb new file mode 100644 index 000000000..3065401e0 --- /dev/null +++ b/lib/fog/aws/parsers/compute/monitor_unmonitor_instances.rb @@ -0,0 +1,31 @@ +module Fog + module Parsers + module Compute + module AWS + class MonitorUnmonitorInstances < Fog::Parsers::Base + def reset + @response = {} + @instance_set = [] + @current_instance_set = {} + end + + def end_element(name) + case name + when 'requestId' + @response['requestId'] = value + when 'instanceId' + @current_instance_set['instanceId'] = value + when 'item' + @instance_set << @current_instance_set + @current_instance_set = {} + when 'state' + @current_instance_set['monitoring'] = value + when 'instancesSet' + @response['instancesSet'] = @instance_set + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/network_acl_parser.rb b/lib/fog/aws/parsers/compute/network_acl_parser.rb new file mode 100644 index 000000000..884354c8d --- /dev/null +++ b/lib/fog/aws/parsers/compute/network_acl_parser.rb @@ -0,0 +1,103 @@ +module Fog + module Parsers + module Compute + module AWS + class NetworkAclParser < Fog::Parsers::Base + def reset_nacl + @network_acl = { 'associationSet' => [], 'entrySet' => [], 'tagSet' => {} } + @association = {} + @entry = { 'icmpTypeCode' => {}, 'portRange' => {} } + @tag = {} + + @in_entry_set = false + @in_association_set = false + @in_tag_set = false + @in_port_range = false + @in_icmp_type_code = false + end + + def reset + reset_nacl + end + + def start_element(name, attrs = []) + super + case name + when 'entrySet' + @in_entry_set = true + when 'associationSet' + @in_association_set = true + when 'tagSet' + @in_tag_set = true + when 'portRange' + @in_port_range = true + when 'icmpTypeCode' + @in_icmp_type_code = true + end + end + + def end_element(name) + if @in_entry_set + if @in_port_range + case name + when 'portRange' + @in_port_range = false + when 'from', 'to' + @entry['portRange'][name] = value.to_i + end + elsif @in_icmp_type_code + case name + when 'icmpTypeCode' + @in_icmp_type_code = false + when 'code', 'type' + @entry['icmpTypeCode'][name] = value.to_i + end + else + case name + when 'entrySet' + @in_entry_set = false + when 'item' + @network_acl['entrySet'] << @entry + @entry = { 'icmpTypeCode' => {}, 'portRange' => {} } + when 'ruleNumber', 'protocol' + @entry[name] = value.to_i + when 'ruleAction', 'cidrBlock' + @entry[name] = value + when 'egress' + @entry[name] = value == 'true' + end + end + elsif @in_association_set + case name + when 'associationSet' + @in_association_set = false + when 'item' + @network_acl['associationSet'] << @association + @association = {} + when 'networkAclAssociationId', 'networkAclId', 'subnetId' + @association[name] = value + end + elsif @in_tag_set + case name + when 'tagSet' + @in_tag_set = false + when 'item' + @network_acl['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + end + else + case name + when 'networkAclId', 'vpcId' + @network_acl[name] = value + when 'default' + @network_acl[name] = value == 'true' + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/network_interface_parser.rb b/lib/fog/aws/parsers/compute/network_interface_parser.rb new file mode 100644 index 000000000..a1bfeb484 --- /dev/null +++ b/lib/fog/aws/parsers/compute/network_interface_parser.rb @@ -0,0 +1,108 @@ +module Fog + module Parsers + module Compute + module AWS + class NetworkInterfaceParser < Fog::Parsers::Base + def reset_nic + @nic = { 'groupSet' => {}, 'attachment' => {}, 'association' => {}, 'tagSet' => {}, 'privateIpAddressesSet' => [] } + @in_tag_set = false + @in_group_set = false + @in_attachment = false + @in_association = false + @in_private_ip_addresses = false + end + + def reset + reset_nic + end + + def start_element(name, attrs = []) + super + case name + when 'tagSet' + @in_tag_set = true + @tag = {} + when 'groupSet' + @in_group_set = true + @group = {} + when 'attachment' + @in_attachment = true + @attachment = {} + when 'association' + @in_association = true + @association = {} + when 'privateIpAddressesSet' + @in_private_ip_addresses = true + @private_ip_addresses = [] + @private_ip_address = {} + end + end + + def end_element(name) + if @in_tag_set + case name + when 'item' + @nic['tagSet'][@tag['key']] = @tag['value'] + @tag = {} + when 'key', 'value' + @tag[name] = value + when 'tagSet' + @in_tag_set = false + end + elsif @in_group_set + case name + when 'item' + @nic['groupSet'][@group['groupId']] = @group['groupName'] + @group = {} + when 'groupId', 'groupName' + @group[name] = value + when 'groupSet' + @in_group_set = false + end + elsif @in_attachment + case name + when 'attachmentId', 'instanceId', 'instanceOwnerId', 'deviceIndex', 'status', 'attachTime', 'deleteOnTermination' + @attachment[name] = value + when 'attachment' + @nic['attachment'] = @attachment + @in_attachment = false + end + elsif @in_association + case name + when 'associationId', 'publicIp', 'ipOwnerId' + @association[name] = value + when 'association' + @nic['association'] = @association + @in_association = false + end + elsif @in_private_ip_addresses + case name + when 'item' + if value + @private_ip_address['item'] = value.strip + else + @private_ip_address['item'] = value + end + @private_ip_addresses << @private_ip_address + @private_ip_address = {} + when 'privateIpAddress', 'privateDnsName', 'primary' + @private_ip_address[name] = value + when 'privateIpAddressesSet' + @nic['privateIpAddresses'] = @private_ip_addresses + @in_private_ip_address = false + end + else + case name + when 'networkInterfaceId', 'subnetId', 'vpcId', 'availabilityZone', 'description', 'ownerId', 'requesterId', + 'requesterManaged', 'status', 'macAddress', 'privateIpAddress', 'privateDnsName' + @nic[name] = value + when 'sourceDestCheck' + @nic['sourceDestCheck'] = (value == 'true') + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/purchase_reserved_instances_offering.rb b/lib/fog/aws/parsers/compute/purchase_reserved_instances_offering.rb new file mode 100644 index 000000000..7f42ff433 --- /dev/null +++ b/lib/fog/aws/parsers/compute/purchase_reserved_instances_offering.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module Compute + module AWS + class PurchaseReservedInstancesOffering < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'reservedInstancesId', 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/register_image.rb b/lib/fog/aws/parsers/compute/register_image.rb new file mode 100644 index 000000000..efdf1ab46 --- /dev/null +++ b/lib/fog/aws/parsers/compute/register_image.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Compute + module AWS + class RegisterImage < Fog::Parsers::Base + def end_element(name) + case name + when 'requestId', 'imageId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/replace_network_acl_association.rb b/lib/fog/aws/parsers/compute/replace_network_acl_association.rb new file mode 100644 index 000000000..6656c7567 --- /dev/null +++ b/lib/fog/aws/parsers/compute/replace_network_acl_association.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module Compute + module AWS + class ReplaceNetworkAclAssociation < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'requestId', 'newAssociationId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/run_instances.rb b/lib/fog/aws/parsers/compute/run_instances.rb new file mode 100644 index 000000000..5e188053e --- /dev/null +++ b/lib/fog/aws/parsers/compute/run_instances.rb @@ -0,0 +1,90 @@ +module Fog + module Parsers + module Compute + module AWS + class RunInstances < Fog::Parsers::Base + def reset + @block_device_mapping = {} + @network_interfaces = {} + @context = [] + @contexts = ['networkInterfaces', 'blockDeviceMapping', 'groupSet', 'placement', 'productCodes'] + @instance = { 'networkInterfaces' => [], 'blockDeviceMapping' => [], 'instanceState' => {}, 'monitoring' => {}, 'placement' => {}, 'productCodes' => [] } + @response = { 'groupSet' => [], 'instancesSet' => [] } + end + + def start_element(name, attrs = []) + super + if @contexts.include?(name) + @context.push(name) + end + end + + def end_element(name) + case name + when 'amiLaunchIndex' + @instance[name] = value.to_i + when 'architecture', 'clientToken', 'dnsName', 'hypervisor', 'imageId', + 'instanceId', 'instanceType', 'ipAddress', 'kernelId', 'keyName', + 'instanceLifecycle', 'privateDnsName', 'privateIpAddress', 'ramdiskId', + 'reason', 'requesterId', 'rootDeviceType', 'sourceDestCheck', + 'spotInstanceRequestId', 'virtualizationType' + @instance[name] = value + when 'availabilityZone', 'tenancy' + @instance['placement'][name] = value + when 'attachTime' + @block_device_mapping[name] = Time.parse(value) + when *@contexts + @context.pop + when 'code' + @instance['instanceState'][name] = value.to_i + when 'deleteOnTermination' + @block_device_mapping[name] = (value == 'true') + @network_interfaces[name] = (value == 'true') + when 'deviceName', 'status', 'volumeId' + @block_device_mapping[name] = value + when 'networkInterfaceId' + @network_interfaces[name] = value + when 'groupId' + @response['groupSet'] << value + when 'groupName' + case @context.last + when 'groupSet' + @response['groupSet'] << value + when 'placement' + @instance['placement'][name] = value + end + when 'item' + case @context.last + when 'blockDeviceMapping' + @instance['blockDeviceMapping'] << @block_device_mapping + @block_device_mapping = {} + when 'networkInterfaces' + @instance['networkInterfaces'] << @network_interfaces + @network_interfaces = {} + when nil + @response['instancesSet'] << @instance + @instance = { 'networkInterfaces' => [], 'blockDeviceMapping' => [], 'instanceState' => {}, 'monitoring' => {}, 'placement' => {}, 'productCodes' => [] } + end + when 'launchTime' + @instance[name] = Time.parse(value) + when 'name' + @instance['instanceState'][name] = value + when 'ownerId', 'requestId', 'reservationId' + @response[name] = value + when 'product_code' + @instance['productCodes'] << value + when 'state' + @instance['monitoring'][name] = (value == 'true') + when 'subnetId' + @response[name] = value + when 'ebsOptimized' + @instance['ebsOptimized'] = (value == 'true') + when 'associatePublicIP' + @instance['associatePublicIP'] = (value == 'true') + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/spot_datafeed_subscription.rb b/lib/fog/aws/parsers/compute/spot_datafeed_subscription.rb new file mode 100644 index 000000000..314c6f322 --- /dev/null +++ b/lib/fog/aws/parsers/compute/spot_datafeed_subscription.rb @@ -0,0 +1,25 @@ +module Fog + module Parsers + module Compute + module AWS + class SpotDatafeedSubscription < Fog::Parsers::Base + def reset + @response = { 'spotDatafeedSubscription' => {} } + end + + def end_element(name) + case name + when 'bucket', 'ownerId', 'prefix', 'state' + @response['spotDatafeedSubscription'][name] = value + when 'code', 'message' + @response['spotDatafeedSubscription']['fault'] ||= {} + @response['spotDatafeedSubscription'][name] = value + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/spot_instance_requests.rb b/lib/fog/aws/parsers/compute/spot_instance_requests.rb new file mode 100644 index 000000000..d8a481b52 --- /dev/null +++ b/lib/fog/aws/parsers/compute/spot_instance_requests.rb @@ -0,0 +1,69 @@ +module Fog + module Parsers + module Compute + module AWS + class SpotInstanceRequests < Fog::Parsers::Base + def reset + @block_device_mapping = {} + @context = [] + @contexts = ['blockDeviceMapping', 'groupSet', 'iamInstanceProfile', 'networkInterfaceSet'] + @spot_instance_request = { 'launchSpecification' => { 'iamInstanceProfile' => {}, 'blockDeviceMapping' => [], 'groupSet' => [] } } + @response = { 'spotInstanceRequestSet' => [] } + end + + def start_element(name, attrs = []) + super + if @contexts.include?(name) + @context.push(name) + end + end + + def end_element(name) + case name + when 'attachTime' + @block_device_mapping[name] = Time.parse(value) + when *@contexts + @context.pop + when 'code', 'message' + @spot_instance_request['fault'] ||= {} + @spot_instance_request['fault'][name] = value + when 'createTime' + @spot_instance_request[name] = Time.parse(value) + when 'deleteOnTermination' + @block_device_mapping[name] = (value == 'true') + when 'deviceName', 'status', 'volumeId' + @block_device_mapping[name] = value + when 'groupId' + if !@context.include?('networkInterfaceSet') + @spot_instance_request['launchSpecification']['groupSet'] << value + end + when 'arn', 'name' + @spot_instance_request['launchSpecification']['iamInstanceProfile'][name] = value + when 'instanceId', 'launchedAvailabilityZone', 'productDescription', 'spotInstanceRequestId', 'state', 'type' + @spot_instance_request[name] = value + when 'item' + case @context.last + when 'blockDeviceMapping' + @spot_instance_request['launchSpecification']['blockDeviceMapping'] << @block_device_mapping + @block_device_mapping = {} + when nil + @response['spotInstanceRequestSet'] << @spot_instance_request + @spot_instance_request = { 'launchSpecification' => { 'iamInstanceProfile' => {}, 'blockDeviceMapping' => [], 'groupSet' => [] } } + end + when 'imageId', 'instanceType', 'keyname', 'subnetId' + @spot_instance_request['launchSpecification'][name] = value + when 'ebsOptimized' + @spot_instance_request['launchSpecification'][name] = value == 'true' + when 'enabled' + @spot_instance_request['launchSpecification']['monitoring'] = (value == 'true') + when 'requestId' + @response[name] = value + when 'spotPrice' + @spot_instance_request[name] = value.to_f + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/start_stop_instances.rb b/lib/fog/aws/parsers/compute/start_stop_instances.rb new file mode 100644 index 000000000..70d1a2d60 --- /dev/null +++ b/lib/fog/aws/parsers/compute/start_stop_instances.rb @@ -0,0 +1,37 @@ +module Fog + module Parsers + module Compute + module AWS + class StartStopInstances < Fog::Parsers::Base + def reset + @instance = { 'currentState' => {}, 'previousState' => {} } + @response = { 'instancesSet' => [] } + @state = nil + end + + def start_element(name, attrs = []) + super + case name + when 'currentState', 'previousState' + @state = name + end + end + + def end_element(name) + case name + when 'code' + @instance[@state][name] = value.to_s + when 'instanceId' + @instance[name] = value + when 'item' + @response['instancesSet'] << @instance + @instance = { 'currentState' => {}, 'previousState' => {} } + when 'name' + @instance[@state][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/compute/terminate_instances.rb b/lib/fog/aws/parsers/compute/terminate_instances.rb new file mode 100644 index 000000000..dfdbb52fa --- /dev/null +++ b/lib/fog/aws/parsers/compute/terminate_instances.rb @@ -0,0 +1,51 @@ +module Fog + module Parsers + module Compute + module AWS + class TerminateInstances < Fog::Parsers::Base + def reset + @instance = { 'previousState' => {}, 'currentState' => {} } + @response = { 'instancesSet' => [] } + end + + def start_element(name, attrs = []) + super + if name == 'previousState' + @in_previous_state = true + elsif name == 'currentState' + @in_current_state = true + end + end + + def end_element(name) + case name + when 'instanceId' + @instance[name] = value + when 'item' + @response['instancesSet'] << @instance + @instance = { 'previousState' => {}, 'currentState' => {} } + when 'code' + if @in_previous_state + @instance['previousState'][name] = value.to_i + elsif @in_current_state + @instance['currentState'][name] = value.to_i + end + when 'name' + if @in_previous_state + @instance['previousState'][name] = value + elsif @in_current_state + @instance['currentState'][name] = value + end + when 'previousState' + @in_previous_state = false + when 'requestId' + @response[name] = value + when 'currentState' + @in_current_state = false + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/change_resource_record_sets.rb b/lib/fog/aws/parsers/dns/change_resource_record_sets.rb new file mode 100644 index 000000000..6f863240e --- /dev/null +++ b/lib/fog/aws/parsers/dns/change_resource_record_sets.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module DNS + module AWS + class ChangeResourceRecordSets < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'Id' + @response[name] = value.sub('/change/', '') + when 'Status', 'SubmittedAt' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/create_health_check.rb b/lib/fog/aws/parsers/dns/create_health_check.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/fog/aws/parsers/dns/create_hosted_zone.rb b/lib/fog/aws/parsers/dns/create_hosted_zone.rb new file mode 100644 index 000000000..a835e63f6 --- /dev/null +++ b/lib/fog/aws/parsers/dns/create_hosted_zone.rb @@ -0,0 +1,51 @@ +module Fog + module Parsers + module DNS + module AWS + class CreateHostedZone < Fog::Parsers::Base + def reset + @hosted_zone = {} + @change_info = {} + @name_servers = [] + @response = {} + @section = :hosted_zone + end + + def end_element(name) + if @section == :hosted_zone + case name + when 'Id' + @hosted_zone[name] = value.sub('/hostedzone/', '') + when 'Name', 'CallerReference', 'Comment' + @hosted_zone[name]= value + when 'HostedZone' + @response['HostedZone'] = @hosted_zone + @hosted_zone = {} + @section = :change_info + end + elsif @section == :change_info + case name + when 'Id' + @change_info[name]= value.sub('/change/', '') + when 'Status', 'SubmittedAt' + @change_info[name] = value + when 'ChangeInfo' + @response['ChangeInfo'] = @change_info + @change_info = {} + @section = :name_servers + end + elsif @section == :name_servers + case name + when 'NameServer' + @name_servers << value + when 'NameServers' + @response['NameServers'] = @name_servers + @name_servers = {} + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/delete_hosted_zone.rb b/lib/fog/aws/parsers/dns/delete_hosted_zone.rb new file mode 100644 index 000000000..0ed53e9fb --- /dev/null +++ b/lib/fog/aws/parsers/dns/delete_hosted_zone.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module DNS + module AWS + class DeleteHostedZone < Fog::Parsers::Base + def reset + @response = {} + @response['ChangeInfo'] = {} + end + + def end_element(name) + case name + when 'Id', 'Status', 'SubmittedAt' + @response['ChangeInfo'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/get_change.rb b/lib/fog/aws/parsers/dns/get_change.rb new file mode 100644 index 000000000..3e46d6a47 --- /dev/null +++ b/lib/fog/aws/parsers/dns/get_change.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module DNS + module AWS + class GetChange < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'Id' + @response[name] = value.sub('/change/', '') + when 'Status', 'SubmittedAt' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/get_hosted_zone.rb b/lib/fog/aws/parsers/dns/get_hosted_zone.rb new file mode 100644 index 000000000..f97f45c10 --- /dev/null +++ b/lib/fog/aws/parsers/dns/get_hosted_zone.rb @@ -0,0 +1,41 @@ +module Fog + module Parsers + module DNS + module AWS + class GetHostedZone < Fog::Parsers::Base + def reset + @hosted_zone = {} + @name_servers = [] + @response = {} + @section = :hosted_zone + end + + def end_element(name) + if @section == :hosted_zone + case name + when 'Id' + @hosted_zone[name]= value.sub('/hostedzone/', '') + when 'Name', 'CallerReference', 'Comment' + @hosted_zone[name]= value + when 'HostedZone' + @response['HostedZone'] = @hosted_zone + @hosted_zone = {} + @section = :name_servers + when 'ResourceRecordSetCount' + @response['ResourceRecordSetCount'] = value.to_i + end + elsif @section == :name_servers + case name + when 'NameServer' + @name_servers << value + when 'NameServers' + @response['NameServers'] = @name_servers + @name_servers = {} + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/health_check.rb b/lib/fog/aws/parsers/dns/health_check.rb new file mode 100644 index 000000000..3b3ccb460 --- /dev/null +++ b/lib/fog/aws/parsers/dns/health_check.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module DNS + module AWS + class HealthCheck < Fog::Parsers::Base + def reset + @health_check = {} + @health_check_config = {} + @response = {} + end + + def end_element(name) + case name + when 'HealthCheck' + @response[name] = @health_check + when 'HealthCheckConfig' + @health_check[name] = @health_check_config + @health_check_config = {} + when 'Id', 'CallerReference' + @health_check[name] = value + when 'HealthCheckVersion' + @health_check[name] = value.to_i + when 'IPAddress', 'Port', 'Type', 'ResourcePath', 'FullyQualifiedDomainName', 'SearchString', 'FailureThreshold' + @health_check_config[name] = value + when 'RequestInterval' + @health_check_config[name] = value.to_i + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/list_health_checks.rb b/lib/fog/aws/parsers/dns/list_health_checks.rb new file mode 100644 index 000000000..a775ada86 --- /dev/null +++ b/lib/fog/aws/parsers/dns/list_health_checks.rb @@ -0,0 +1,41 @@ +module Fog + module Parsers + module DNS + module AWS + class ListHealthChecks < Fog::Parsers::Base + def reset + @health_checks = [] + @health_check = {} + @health_check_config = {} + @response = {} + end + + def end_element(name) + case name + when 'HealthChecks' + @response['HealthChecks'] = @health_checks + when 'HealthCheck' + @health_checks << @health_check + @health_check = {} + when 'HealthCheckConfig' + @health_check[name] = @health_check_config + @health_check_config = {} + when 'Id', 'CallerReference' + @health_check[name] = value + when 'HealthCheckVersion' + @health_check[name] = value.to_i + when 'IPAddress', 'Port', 'Type', 'ResourcePath', 'FullyQualifiedDomainName', 'SearchString', 'FailureThreshold' + @health_check_config[name] = value + when 'RequestInterval' + @health_check_config[name] = value.to_i + when 'MaxItems' + @response[name] = value.to_i + when 'IsTruncated', 'Marker', 'NextMarker' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/list_hosted_zones.rb b/lib/fog/aws/parsers/dns/list_hosted_zones.rb new file mode 100644 index 000000000..fd709b574 --- /dev/null +++ b/lib/fog/aws/parsers/dns/list_hosted_zones.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module DNS + module AWS + class ListHostedZones < Fog::Parsers::Base + def reset + @hosted_zones = [] + @zone = {} + @response = {} + end + + def end_element(name) + case name + when 'Id' + @zone[name] = value.sub('/hostedzone/', '') + when 'Name', 'CallerReference', 'Comment' + @zone[name] = value + when 'HostedZone' + @hosted_zones << @zone + @zone = {} + when 'HostedZones' + @response['HostedZones'] = @hosted_zones + when 'MaxItems' + @response[name] = value.to_i + when 'IsTruncated', 'Marker', 'NextMarker' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/dns/list_resource_record_sets.rb b/lib/fog/aws/parsers/dns/list_resource_record_sets.rb new file mode 100644 index 000000000..98385e586 --- /dev/null +++ b/lib/fog/aws/parsers/dns/list_resource_record_sets.rb @@ -0,0 +1,58 @@ +module Fog + module Parsers + module DNS + module AWS + class ListResourceRecordSets < Fog::Parsers::Base + def reset + @resource_record = [] + @resource_record_set = {} + @resource_record_set['ResourceRecords'] = [] + @alias_target = {} + @geo_location = {} + @response = {} + @response['ResourceRecordSets'] = [] + @section = :resource_record_set + end + + def end_element(name) + if @section == :resource_record_set + case name + when 'Type', 'TTL', 'SetIdentifier', 'Weight', 'Region', 'HealthCheckId', 'Failover' + @resource_record_set[name] = value + when 'Name' + @resource_record_set[name] = value.gsub('\\052', '*') + when 'Value' + @resource_record_set['ResourceRecords'] << value + when 'AliasTarget' + @resource_record_set[name] = @alias_target + @alias_target = {} + when 'HostedZoneId', 'DNSName', 'EvaluateTargetHealth' + @alias_target[name] = value + when 'GeoLocation' + @resource_record_set[name] = @geo_location + @geo_location = {} + when 'ContinentCode', 'CountryCode', 'SubdivisionCode' + @geo_location[name] = value + when 'ResourceRecordSet' + @response['ResourceRecordSets'] << @resource_record_set + @resource_record_set = {} + @resource_record_set['ResourceRecords'] = [] + when 'ResourceRecordSets' + @section = :main + end + elsif @section == :main + case name + when 'MaxItems' + @response[name] = value.to_i + when 'NextRecordName', 'NextRecordType', 'NextRecordIdentifier' + @response[name] = value + when 'IsTruncated' + @response[name] = value == 'true' + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/authorize_cache_security_group_ingress.rb b/lib/fog/aws/parsers/elasticache/authorize_cache_security_group_ingress.rb new file mode 100644 index 000000000..c4f19d297 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/authorize_cache_security_group_ingress.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/security_group_parser' + + class AuthorizeCacheSecurityGroupIngress < Fog::Parsers::AWS::Elasticache::SecurityGroupParser + def end_element(name) + case name + when 'CacheSecurityGroup' then + @response['CacheSecurityGroup'] = @security_group + reset_security_group + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/base.rb b/lib/fog/aws/parsers/elasticache/base.rb new file mode 100644 index 000000000..af49f533b --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/base.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module Elasticache + # Base parser for ResponseMetadata, RequestId + class Base < Fog::Parsers::Base + def reset + super + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb b/lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb new file mode 100644 index 000000000..cfc4c6871 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb @@ -0,0 +1,77 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/base' + + class CacheClusterParser < Base + def reset + super + reset_cache_cluster + end + + def reset_cache_cluster + @cache_cluster = { + 'CacheSecurityGroups' => [], + 'CacheNodes' => [], + 'CacheParameterGroup' => {} + } + end + + def start_element(name, attrs = []) + super + case name + when 'CacheSecurityGroup'; then @security_group = {} + when 'CacheNode'; then @cache_node = {} + when 'PendingModifiedValues'; then @pending_values = {} + end + end + + def end_element(name) + case name + when 'AutoMinorVersionUpgrade', 'CacheClusterId', + 'CacheClusterStatus', 'CacheNodeType', 'Engine', + 'PreferredAvailabilityZone', 'PreferredMaintenanceWindow' + @cache_cluster[name] = value + when 'EngineVersion', 'CacheNodeIdsToRemoves' + if @pending_values + @pending_values[name] = value ? value.strip : name + else + @cache_cluster[name] = value + end + when 'NumCacheNodes' + if @pending_values + @pending_values[name] = value.to_i + else + @cache_cluster[name] = value.to_i + end + when 'CacheClusterCreateTime' + @cache_cluster[name] = DateTime.parse(value) + when 'CacheSecurityGroup' + @cache_cluster["#{name}s"] << @security_group unless @security_group.empty? + when 'CacheSecurityGroupName', 'Status', 'CacheSubnetGroupName' + @cache_cluster[name] = value + when 'CacheNode' + @cache_cluster["#{name}s"] << @cache_node unless @cache_node.empty? + @cache_node = nil + when'PendingModifiedValues' + @cache_cluster[name] = @pending_values + @pending_values = nil + when 'CacheNodeCreateTime', 'CacheNodeStatus', 'Address', + 'ParameterGroupStatus', 'Port', 'CacheNodeId' + if @cache_node + @cache_node[name] = value ? value.strip : name + elsif @pending_values + @pending_values[name] = value ? value.strip : name + end + when 'CacheNodeIdsToReboots', 'CacheParameterGroupName', 'ParameterApplyStatus' + @cache_cluster['CacheParameterGroup'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/create_cache_subnet_group.rb b/lib/fog/aws/parsers/elasticache/create_cache_subnet_group.rb new file mode 100644 index 000000000..765191b18 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/create_cache_subnet_group.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/subnet_group_parser' + + class CreateCacheSubnetGroup < Fog::Parsers::AWS::Elasticache::SubnetGroupParser + def reset + @response = { 'CreateCacheSubnetGroupResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSubnetGroup' then + @response['CreateCacheSubnetGroupResult']['CacheSubnetGroup'] = @cache_subnet_group + @cache_subnet_group = fresh_subnet_group + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb b/lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb new file mode 100644 index 000000000..9c4facdcd --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/cache_cluster_parser' + + class DescribeCacheClusters < CacheClusterParser + def reset + super + @response['CacheClusters'] = [] + end + + def end_element(name) + case name + when 'CacheCluster' + @response["#{name}s"] << @cache_cluster + reset_cache_cluster + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_cache_parameters.rb b/lib/fog/aws/parsers/elasticache/describe_cache_parameters.rb new file mode 100644 index 000000000..f651f0fe3 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_cache_parameters.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/engine_defaults_parser' + + class DescribeCacheParameters < EngineDefaultsParser + def end_element(name) + case name + when 'DescribeCacheParametersResult' + @response[name] = @engine_defaults + reset_engine_defaults + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_cache_subnet_groups.rb b/lib/fog/aws/parsers/elasticache/describe_cache_subnet_groups.rb new file mode 100644 index 000000000..f2368ba0c --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_cache_subnet_groups.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/subnet_group_parser' + + class DescribeCacheSubnetGroups < Fog::Parsers::AWS::Elasticache::SubnetGroupParser + def reset + @response = { 'DescribeCacheSubnetGroupsResult' => {'CacheSubnetGroups' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'CacheSubnetGroup' + @response['DescribeCacheSubnetGroupsResult']['CacheSubnetGroups'] << @cache_subnet_group + @cache_subnet_group = fresh_subnet_group + when 'Marker' + @response['DescribeCacheSubnetGroupsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_engine_default_parameters.rb b/lib/fog/aws/parsers/elasticache/describe_engine_default_parameters.rb new file mode 100644 index 000000000..9773140aa --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_engine_default_parameters.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/engine_defaults_parser' + + class DescribeEngineDefaultParameters < EngineDefaultsParser + def end_element(name) + case name + when 'EngineDefaults' + @response[name] = @engine_defaults + reset_engine_defaults + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_parameter_groups.rb b/lib/fog/aws/parsers/elasticache/describe_parameter_groups.rb new file mode 100644 index 000000000..b4fa476cc --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_parameter_groups.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/parameter_group_parser' + + class DescribeParameterGroups < ParameterGroupParser + def reset + super + @response['CacheParameterGroups'] = [] + end + + def end_element(name) + case name + when 'CacheParameterGroup' + @response["#{name}s"] << @parameter_group + reset_parameter_group + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_reserved_cache_nodes.rb b/lib/fog/aws/parsers/elasticache/describe_reserved_cache_nodes.rb new file mode 100644 index 000000000..dc942da60 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_reserved_cache_nodes.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module Elasticache + class DescribeReservedCacheNodes < Fog::Parsers::Base + def reset + @reserved_node = {} + @response = { 'ReservedCacheNodes' => [] } + end + + def end_element(name) + case name + when 'ReservedCacheNodeId', 'ReservedCacheNodesOfferingId', 'CacheNodeType', 'ProductDescription', 'State' + @reserved_node[name] = @value + when 'Duration', 'CacheNodeCount' + @reserved_node[name] = @value.to_i + when 'FixedPrice', 'UsagePrice' + @reserved_node[name] = @value.to_f + when 'ReservedCacheNode' + @response['ReservedCacheNodes'] << @reserved_node + @reserved_node = {} + when 'Marker' + @response[name] = @value + when 'StartTime' + @reserved_node[name] = Time.parse(@value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_security_groups.rb b/lib/fog/aws/parsers/elasticache/describe_security_groups.rb new file mode 100644 index 000000000..6651eaf7c --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_security_groups.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/security_group_parser' + + class DescribeSecurityGroups < SecurityGroupParser + def reset + super + @response['CacheSecurityGroups'] = [] + end + + def end_element(name) + case name + when 'CacheSecurityGroup' + @response["#{name}s"] << @security_group + reset_security_group + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/engine_defaults_parser.rb b/lib/fog/aws/parsers/elasticache/engine_defaults_parser.rb new file mode 100644 index 000000000..7d742a577 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/engine_defaults_parser.rb @@ -0,0 +1,58 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/base' + + class EngineDefaultsParser < Base + def reset + super + reset_engine_defaults + end + + def reset_engine_defaults + @engine_defaults = { + 'CacheNodeTypeSpecificParameters' => [], + 'Parameters' => [], + } + end + + def start_element(name, attrs = []) + case name + when 'CacheNodeTypeSpecificParameter', 'Parameter' + @parameter = {} + when 'CacheNodeTypeSpecificValues' + @parameter[name] = [] + when 'CacheNodeTypeSpecificValue' + @node_specific_value = {} + else + super + end + end + + def end_element(name) + case name + when 'CacheParameterGroupFamily' + @engine_defaults[name] = value + when 'CacheNodeTypeSpecificParameter', 'Parameter' + if not @parameter.empty? + @engine_defaults["#{name}s"] << @parameter + end + when 'AllowedValues', 'DataType', 'Description', 'IsModifiable', + 'MinimumEngineVersion', 'ParameterName', 'ParameterValue', 'Source' + @parameter[name] = value + when 'CacheNodeType', 'Value' + @node_specific_value[name] = value + when 'CacheNodeTypeSpecificValue' + if not @node_specific_value.empty? + @parameter["#{name}s"] << @node_specific_value + end + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/event_list.rb b/lib/fog/aws/parsers/elasticache/event_list.rb new file mode 100644 index 000000000..1a30c11ae --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/event_list.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/base' + + class EventListParser < Base + def reset + super + @response['Events'] = [] + end + + def start_element(name, attrs = []) + super + case name + when 'Event'; then @event = {} + end + end + + def end_element(name) + case name + when 'Date' + @event[name] = DateTime.parse(value.strip) + when 'Message', 'SourceIdentifier', 'SourceType' + @event[name] = value ? value.strip : name + when 'Event' + @response['Events'] << @event unless @event.empty? + when 'IsTruncated', 'Marker', 'NextMarker' + @response[name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/modify_parameter_group.rb b/lib/fog/aws/parsers/elasticache/modify_parameter_group.rb new file mode 100644 index 000000000..4853264d1 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/modify_parameter_group.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/parameter_group_parser' + + class ModifyParameterGroup < ParameterGroupParser + def reset + super + @response['ModifyCacheParameterGroupResult'] = [] + end + + def end_element(name) + case name + when 'ModifyCacheParameterGroupResult' + @response[name] = @parameter_group + reset_parameter_group + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/parameter_group_parser.rb b/lib/fog/aws/parsers/elasticache/parameter_group_parser.rb new file mode 100644 index 000000000..0b8e8acc4 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/parameter_group_parser.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/base' + + class ParameterGroupParser < Base + def reset + super + reset_parameter_group + end + + def reset_parameter_group + @parameter_group = {} + end + + def end_element(name) + case name + when 'Description', 'CacheParameterGroupName', 'CacheParameterGroupFamily' + @parameter_group[name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/reset_parameter_group.rb b/lib/fog/aws/parsers/elasticache/reset_parameter_group.rb new file mode 100644 index 000000000..ff49e00e4 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/reset_parameter_group.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/parameter_group_parser' + + class ResetParameterGroup < ParameterGroupParser + def reset + super + @response['ResetCacheParameterGroupResult'] = [] + end + + def end_element(name) + case name + when 'ResetCacheParameterGroupResult' + @response[name] = @parameter_group + reset_parameter_group + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/security_group_parser.rb b/lib/fog/aws/parsers/elasticache/security_group_parser.rb new file mode 100644 index 000000000..b9b9f3e1c --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/security_group_parser.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/base' + + class SecurityGroupParser < Fog::Parsers::Base + def reset + super + reset_security_group + end + + def reset_security_group + @security_group = {'EC2SecurityGroups' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'EC2SecurityGroup'; then @ec2_group = {} + end + end + + def end_element(name) + case name + when 'Description', 'CacheSecurityGroupName', 'OwnerId' + @security_group[name] = value + when 'EC2SecurityGroup' + @security_group["#{name}s"] << @ec2_group unless @ec2_group.empty? + when 'EC2SecurityGroupName', 'EC2SecurityGroupOwnerId', 'Status' + @ec2_group[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/single_cache_cluster.rb b/lib/fog/aws/parsers/elasticache/single_cache_cluster.rb new file mode 100644 index 000000000..01abd2891 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/single_cache_cluster.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/cache_cluster_parser' + + class SingleCacheCluster < CacheClusterParser + def end_element(name) + case name + when 'CacheCluster' + @response[name] = @cache_cluster + reset_cache_cluster + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/single_parameter_group.rb b/lib/fog/aws/parsers/elasticache/single_parameter_group.rb new file mode 100644 index 000000000..36b0403da --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/single_parameter_group.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/parameter_group_parser' + + class SingleParameterGroup < ParameterGroupParser + def end_element(name) + case name + when 'CacheParameterGroup' + @response[name] = @parameter_group + reset_parameter_group + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/single_security_group.rb b/lib/fog/aws/parsers/elasticache/single_security_group.rb new file mode 100644 index 000000000..8c03d3042 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/single_security_group.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/security_group_parser' + + class SingleSecurityGroup < SecurityGroupParser + def reset + super + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'CacheSecurityGroup' + @response[name] = @security_group + reset_security_group + + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/subnet_group_parser.rb b/lib/fog/aws/parsers/elasticache/subnet_group_parser.rb new file mode 100644 index 000000000..c2c220c6f --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/subnet_group_parser.rb @@ -0,0 +1,35 @@ +module Fog + module Parsers + module AWS + module Elasticache + class SubnetGroupParser < Fog::Parsers::Base + def reset + @cache_subnet_group = fresh_subnet_group + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'VpcId' then @cache_subnet_group['VpcId'] = value + when 'SubnetGroupStatus' then @cache_subnet_group['SubnetGroupStatus'] = value + when 'CacheSubnetGroupDescription' then @cache_subnet_group['CacheSubnetGroupDescription'] = value + when 'CacheSubnetGroupName' then @cache_subnet_group['CacheSubnetGroupName'] = value + when 'SubnetIdentifier' then @cache_subnet_group['Subnets'] << value + when 'Marker' + @response['DescribeCacheSubnetGroupsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + + def fresh_subnet_group + {'Subnets' => []} + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/apply_security_groups_to_load_balancer.rb b/lib/fog/aws/parsers/elb/apply_security_groups_to_load_balancer.rb new file mode 100644 index 000000000..4d2124f9a --- /dev/null +++ b/lib/fog/aws/parsers/elb/apply_security_groups_to_load_balancer.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class ApplySecurityGroupsToLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'ApplySecurityGroupsToLoadBalancerResult' => { 'SecurityGroups' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'member' + @response['ApplySecurityGroupsToLoadBalancerResult']['SecurityGroups'] << value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/attach_load_balancer_to_subnets.rb b/lib/fog/aws/parsers/elb/attach_load_balancer_to_subnets.rb new file mode 100644 index 000000000..f2450fffb --- /dev/null +++ b/lib/fog/aws/parsers/elb/attach_load_balancer_to_subnets.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class AttachLoadBalancerToSubnets < Fog::Parsers::Base + def reset + @response = { 'AttachLoadBalancerToSubnetsResult' => { 'Subnets' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'member' + @response['AttachLoadBalancerToSubnetsResult']['Subnets'] << value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/configure_health_check.rb b/lib/fog/aws/parsers/elb/configure_health_check.rb new file mode 100644 index 000000000..ef3b0451f --- /dev/null +++ b/lib/fog/aws/parsers/elb/configure_health_check.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module ELB + class ConfigureHealthCheck < Fog::Parsers::Base + def reset + @health_check = {} + @response = { 'ConfigureHealthCheckResult' => {}, 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'Target' + @health_check[name] = value + when 'Interval', 'Timeout', 'UnhealthyThreshold', 'HealthyThreshold' + @health_check[name] = value.to_i + + when 'HealthCheck' + @response['ConfigureHealthCheckResult'][name] = @health_check + + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/create_load_balancer.rb b/lib/fog/aws/parsers/elb/create_load_balancer.rb new file mode 100644 index 000000000..0b38943b7 --- /dev/null +++ b/lib/fog/aws/parsers/elb/create_load_balancer.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class CreateLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'CreateLoadBalancerResult' => {}, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'DNSName' + @response['CreateLoadBalancerResult'][name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/delete_load_balancer.rb b/lib/fog/aws/parsers/elb/delete_load_balancer.rb new file mode 100644 index 000000000..ab0fe04cd --- /dev/null +++ b/lib/fog/aws/parsers/elb/delete_load_balancer.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module ELB + class DeleteLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'DeleteLoadBalancerResult' => nil, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/deregister_instances_from_load_balancer.rb b/lib/fog/aws/parsers/elb/deregister_instances_from_load_balancer.rb new file mode 100644 index 000000000..7ae417121 --- /dev/null +++ b/lib/fog/aws/parsers/elb/deregister_instances_from_load_balancer.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class DeregisterInstancesFromLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'DeregisterInstancesFromLoadBalancerResult' => { 'Instances' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'InstanceId' + @response['DeregisterInstancesFromLoadBalancerResult']['Instances'] << {name => value} + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/describe_instance_health.rb b/lib/fog/aws/parsers/elb/describe_instance_health.rb new file mode 100644 index 000000000..4e0f9b88a --- /dev/null +++ b/lib/fog/aws/parsers/elb/describe_instance_health.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module ELB + class DescribeInstanceHealth < Fog::Parsers::Base + def reset + @response = { 'DescribeInstanceHealthResult' => { 'InstanceStates' => [] }, 'ResponseMetadata' => {} } + @instance_state = {} + end + + def end_element(name) + case name + when 'Description', 'State', 'InstanceId', 'ReasonCode' + @instance_state[name] = value + when 'member' + @response['DescribeInstanceHealthResult']['InstanceStates'] << @instance_state + @instance_state = {} + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/describe_load_balancer_attributes.rb b/lib/fog/aws/parsers/elb/describe_load_balancer_attributes.rb new file mode 100644 index 000000000..d282070a4 --- /dev/null +++ b/lib/fog/aws/parsers/elb/describe_load_balancer_attributes.rb @@ -0,0 +1,54 @@ +module Fog + module Parsers + module AWS + module ELB + class DescribeLoadBalancerAttributes < Fog::Parsers::Base + def reset + @response = { 'DescribeLoadBalancerAttributesResult' => { 'LoadBalancerAttributes' => {} }, 'ResponseMetadata' => {} } + @stack = [] + end + + def start_element(name, attrs = []) + super + case name + when 'ConnectionDraining' + @connection_draining = {} + when 'CrossZoneLoadBalancing' + @cross_zone_load_balancing = {} + when 'ConnectionSettings' + @connection_settings = {} + end + end + + def end_element(name) + case name + when 'Enabled' + if @cross_zone_load_balancing + @cross_zone_load_balancing['Enabled'] = value == 'true' ? true : false + elsif @connection_draining + @connection_draining['Enabled'] = value == 'true' ? true : false + end + when 'IdleTimeout' + @connection_settings['IdleTimeout'] = value.to_i + when 'Timeout' + if @connection_draining + @connection_draining['Timeout'] = value.to_i + end + when 'ConnectionDraining' + @response['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['ConnectionDraining'] = @connection_draining + @connection_draining = nil + when 'CrossZoneLoadBalancing' + @response['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['CrossZoneLoadBalancing'] = @cross_zone_load_balancing + @cross_zone_load_balancing = nil + when 'ConnectionSettings' + @response['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes']['ConnectionSettings'] = @connection_settings + @connection_settings = nil + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/describe_load_balancer_policies.rb b/lib/fog/aws/parsers/elb/describe_load_balancer_policies.rb new file mode 100644 index 000000000..ecdbd68ff --- /dev/null +++ b/lib/fog/aws/parsers/elb/describe_load_balancer_policies.rb @@ -0,0 +1,60 @@ +module Fog + module Parsers + module AWS + module ELB + class DescribeLoadBalancerPolicies < Fog::Parsers::Base + def reset + reset_policy + reset_policy_attribute_description + @results = { 'PolicyDescriptions' => [] } + @response = { 'DescribeLoadBalancerPoliciesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_policy + @policy = { 'PolicyAttributeDescriptions' => [], 'PolicyName' => '', 'PolicyTypeName' => '' } + end + + def reset_policy_attribute_description + @policy_attribute_description = { 'AttributeName' => '', 'AttributeValue' => '' } + end + + def start_element(name, attrs = []) + super + case name + when 'PolicyAttributeDescriptions' + @in_policy_attributes = true + end + end + + def end_element(name) + case name + when 'member' + if @in_policy_attributes + @policy['PolicyAttributeDescriptions'] << @policy_attribute_description + reset_policy_attribute_description + elsif !@in_policy_attributes + @results['PolicyDescriptions'] << @policy + reset_policy + end + + when 'PolicyName', 'PolicyTypeName' + @policy[name] = value + + when 'PolicyAttributeDescriptions' + @in_policy_attributes = false + + when 'AttributeName', 'AttributeValue' + @policy_attribute_description[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeLoadBalancerPoliciesResponse' + @response['DescribeLoadBalancerPoliciesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/describe_load_balancer_policy_types.rb b/lib/fog/aws/parsers/elb/describe_load_balancer_policy_types.rb new file mode 100644 index 000000000..11170c525 --- /dev/null +++ b/lib/fog/aws/parsers/elb/describe_load_balancer_policy_types.rb @@ -0,0 +1,66 @@ +module Fog + module Parsers + module AWS + module ELB + class DescribeLoadBalancerPolicyTypes < Fog::Parsers::Base + def reset + reset_policy_type + reset_policy_attribute_type_description + @results = { 'PolicyTypeDescriptions' => [] } + @response = { 'DescribeLoadBalancerPolicyTypesResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_policy_type + @policy_type = { 'Description' => '', 'PolicyAttributeTypeDescriptions' => [], 'PolicyTypeName' => '' } + end + + def reset_policy_attribute_type_description + @policy_attribute_type_description = { 'AttributeName' => '', 'AttributeType' => '', 'Cardinality' => '', 'DefaultValue' => '', 'Description' => '' } + end + + def start_element(name, attrs = []) + super + case name + when 'PolicyAttributeTypeDescriptions' + @in_policy_attribute_types = true + end + end + + def end_element(name) + case name + when 'member' + if @in_policy_attribute_types + @policy_type['PolicyAttributeTypeDescriptions'] << @policy_attribute_type_description + reset_policy_attribute_type_description + elsif !@in_policy_attribute_types + @results['PolicyTypeDescriptions'] << @policy_type + reset_policy_type + end + + when 'Description' + if @in_policy_attribute_types + @policy_attribute_type_description[name] = value + else + @policy_type[name] = value + end + when 'PolicyTypeName' + @policy_type[name] = value + + when 'PolicyAttributeTypeDescriptions' + @in_policy_attribute_types = false + + when 'AttributeName', 'AttributeType', 'Cardinality', 'DefaultValue' + @policy_attribute_type_description[name] = value + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'DescribeLoadBalancerPolicyTypesResponse' + @response['DescribeLoadBalancerPolicyTypesResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/describe_load_balancers.rb b/lib/fog/aws/parsers/elb/describe_load_balancers.rb new file mode 100644 index 000000000..7e539e51a --- /dev/null +++ b/lib/fog/aws/parsers/elb/describe_load_balancers.rb @@ -0,0 +1,167 @@ +module Fog + module Parsers + module AWS + module ELB + class DescribeLoadBalancers < Fog::Parsers::Base + def reset + reset_load_balancer + reset_listener_description + reset_stickiness_policy + reset_backend_server_description + @results = { 'LoadBalancerDescriptions' => [] } + @response = { 'DescribeLoadBalancersResult' => {}, 'ResponseMetadata' => {} } + end + + def reset_load_balancer + @load_balancer = { 'Subnets' => [], 'SecurityGroups' => [], 'ListenerDescriptions' => [], 'Instances' => [], 'AvailabilityZones' => [], 'Policies' => {'AppCookieStickinessPolicies' => [], 'LBCookieStickinessPolicies' => [], 'OtherPolicies' => []}, 'HealthCheck' => {}, 'SourceSecurityGroup' => {}, 'BackendServerDescriptions' => [] } + end + + def reset_listener_description + @listener_description = { 'PolicyNames' => [], 'Listener' => {} } + end + + def reset_backend_server_description + @backend_server_description = {} + end + + def reset_stickiness_policy + @stickiness_policy = {} + end + + def start_element(name, attrs = []) + super + case name + when 'ListenerDescriptions' + @in_listeners = true + when 'Instances' + @in_instances = true + when 'AvailabilityZones' + @in_availability_zones = true + when 'SecurityGroups' + @in_security_groups = true + when 'Subnets' + @in_subnets = true + when 'PolicyNames' + @in_policy_names = true + when 'Policies' + @in_policies = true + when 'LBCookieStickinessPolicies' + @in_lb_cookies = true + when 'AppCookieStickinessPolicies' + @in_app_cookies = true + when 'AppCookieStickinessPolicies' + @in_app_cookies = true + when 'OtherPolicies' + @in_other_policies = true + when 'BackendServerDescriptions' + @in_backend_server_descriptions = true + end + end + + def end_element(name) + case name + when 'member' + if @in_policy_names && @in_listeners + @listener_description['PolicyNames'] << value + elsif @in_availability_zones + @load_balancer['AvailabilityZones'] << value + elsif @in_security_groups + @load_balancer['SecurityGroups'] << value + elsif @in_subnets + @load_balancer['Subnets'] << value + elsif @in_listeners + @load_balancer['ListenerDescriptions'] << @listener_description + reset_listener_description + elsif @in_app_cookies + @load_balancer['Policies']['AppCookieStickinessPolicies'] << @stickiness_policy + reset_stickiness_policy + elsif @in_lb_cookies + @load_balancer['Policies']['LBCookieStickinessPolicies'] << @stickiness_policy + reset_stickiness_policy + elsif @in_other_policies + @load_balancer['Policies']['OtherPolicies'] << value + elsif @in_backend_server_descriptions && @in_policy_names + @backend_server_description['PolicyNames'] ||= [] + @backend_server_description['PolicyNames'] << value + elsif @in_backend_server_descriptions && !@in_policy_names + @load_balancer['BackendServerDescriptions'] << @backend_server_description + reset_backend_server_description + elsif !@in_instances && !@in_policies && !@in_backend_server_descriptions + @results['LoadBalancerDescriptions'] << @load_balancer + reset_load_balancer + end + + when 'BackendServerDescriptions' + @in_backend_server_descriptions = false + + when 'InstancePort' + if @in_backend_server_descriptions + @backend_server_description[name] = value.to_i + elsif @in_listeners + @listener_description['Listener'][name] = value.to_i + end + + when 'CanonicalHostedZoneName', 'CanonicalHostedZoneNameID', 'LoadBalancerName', 'DNSName', 'Scheme' + @load_balancer[name] = value + when 'CreatedTime' + @load_balancer[name] = Time.parse(value) + + when 'ListenerDescriptions' + @in_listeners = false + when 'PolicyNames' + @in_policy_names = false + when 'Protocol', 'SSLCertificateId', 'InstanceProtocol' + @listener_description['Listener'][name] = value + when 'LoadBalancerPort' + @listener_description['Listener'][name] = value.to_i + + when 'Instances' + @in_instances = false + when 'InstanceId' + @load_balancer['Instances'] << value + when 'VPCId' + @load_balancer[name] = value + + when 'AvailabilityZones' + @in_availability_zones = false + when 'SecurityGroups' + @in_security_groups = false + when 'Subnets' + @in_subnets = false + + when 'Policies' + @in_policies = false + when 'AppCookieStickinessPolicies' + @in_app_cookies = false + when 'LBCookieStickinessPolicies' + @in_lb_cookies = false + when 'OtherPolicies' + @in_other_policies = false + + when 'OwnerAlias', 'GroupName' + @load_balancer['SourceSecurityGroup'][name] = value + + when 'Interval', 'HealthyThreshold', 'Timeout', 'UnhealthyThreshold' + @load_balancer['HealthCheck'][name] = value.to_i + when 'Target' + @load_balancer['HealthCheck'][name] = value + + when 'PolicyName', 'CookieName' + @stickiness_policy[name] = value + when 'CookieExpirationPeriod' + @stickiness_policy[name] = value.to_i + + when 'RequestId' + @response['ResponseMetadata'][name] = value + + when 'NextMarker' + @results['NextMarker'] = value + when 'DescribeLoadBalancersResponse' + @response['DescribeLoadBalancersResult'] = @results + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/describe_tags.rb b/lib/fog/aws/parsers/elb/describe_tags.rb new file mode 100644 index 000000000..7859f88c5 --- /dev/null +++ b/lib/fog/aws/parsers/elb/describe_tags.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Compute + module AWS + class DescribeTags < Fog::Parsers::Base + def reset + @tag = {} + @response = { 'tagSet' => [] } + end + + def end_element(name) + case name + when 'resourceId', 'resourceType', 'key', 'value' + @tag[name] = value + when 'item' + @response['tagSet'] << @tag + @tag = {} + when 'requestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/detach_load_balancer_from_subnets.rb b/lib/fog/aws/parsers/elb/detach_load_balancer_from_subnets.rb new file mode 100644 index 000000000..a687dc176 --- /dev/null +++ b/lib/fog/aws/parsers/elb/detach_load_balancer_from_subnets.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class DetachLoadBalancerFromSubnets < Fog::Parsers::Base + def reset + @response = { 'DetachLoadBalancerFromSubnetsResult' => { 'Subnets' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'member' + @response['DetachLoadBalancerFromSubnetsResult']['Subnets'] << value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/disable_availability_zones_for_load_balancer.rb b/lib/fog/aws/parsers/elb/disable_availability_zones_for_load_balancer.rb new file mode 100644 index 000000000..223ee399d --- /dev/null +++ b/lib/fog/aws/parsers/elb/disable_availability_zones_for_load_balancer.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class DisableAvailabilityZonesForLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'DisableAvailabilityZonesForLoadBalancerResult' => { 'AvailabilityZones' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'member' + @response['DisableAvailabilityZonesForLoadBalancerResult']['AvailabilityZones'] << value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/empty.rb b/lib/fog/aws/parsers/elb/empty.rb new file mode 100644 index 000000000..7699b4843 --- /dev/null +++ b/lib/fog/aws/parsers/elb/empty.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module ELB + class Empty < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/enable_availability_zones_for_load_balancer.rb b/lib/fog/aws/parsers/elb/enable_availability_zones_for_load_balancer.rb new file mode 100644 index 000000000..c2d74a9ae --- /dev/null +++ b/lib/fog/aws/parsers/elb/enable_availability_zones_for_load_balancer.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class EnableAvailabilityZonesForLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'EnableAvailabilityZonesForLoadBalancerResult' => { 'AvailabilityZones' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'member' + @response['EnableAvailabilityZonesForLoadBalancerResult']['AvailabilityZones'] << value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/register_instances_with_load_balancer.rb b/lib/fog/aws/parsers/elb/register_instances_with_load_balancer.rb new file mode 100644 index 000000000..00e3c723d --- /dev/null +++ b/lib/fog/aws/parsers/elb/register_instances_with_load_balancer.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module ELB + class RegisterInstancesWithLoadBalancer < Fog::Parsers::Base + def reset + @response = { 'RegisterInstancesWithLoadBalancerResult' => { 'Instances' => [] }, 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'InstanceId' + @response['RegisterInstancesWithLoadBalancerResult']['Instances'] << {name => value} + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elb/tag_list_parser.rb b/lib/fog/aws/parsers/elb/tag_list_parser.rb new file mode 100644 index 000000000..376012a5b --- /dev/null +++ b/lib/fog/aws/parsers/elb/tag_list_parser.rb @@ -0,0 +1,57 @@ +module Fog + module Parsers + module AWS + module ELB + # parses an XML-formatted list of resource tags from Aws + class TagListParser < Fog::Parsers::Base + + # each tag is modeled as a String pair (2-element Array) + def reset + @this_key = nil + @this_value = nil + @tags = Hash.new + @response = { 'DescribeTagsResult' => { 'LoadBalancers' => [] }, 'ResponseMetadata' => {} } + @in_tags = false + end + + def start_element(name, attrs = []) + super + case name + when 'member' + unless @in_tags + @load_balancer_name = nil + @tags = {} + end + when 'Tags' + @in_tags = true + end + end + + def end_element(name) + super + case name + when 'member' + if @in_tags + @tags[@this_key] = @this_value + @this_key, @this_value = nil, nil + else + @response['DescribeTagsResult']['LoadBalancers'] << { 'Tags' => @tags, 'LoadBalancerName' => @load_balancer_name } + end + when 'Key' + @this_key = value + when 'Value' + @this_value = value + when 'LoadBalancerName' + @load_balancer_name = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + when 'Tags' + @in_tags = false + end + end + + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/add_instance_groups.rb b/lib/fog/aws/parsers/emr/add_instance_groups.rb new file mode 100644 index 000000000..2c8a507c0 --- /dev/null +++ b/lib/fog/aws/parsers/emr/add_instance_groups.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module EMR + class AddInstanceGroups < Fog::Parsers::Base + def start_element(name, attrs = []) + super + case name + when 'InstanceGroupIds' + @response['InstanceGroupIds'] = [] + end + end + + def end_element(name) + case name + when 'JobFlowId' + @response[name] = value + when 'member' + @response['InstanceGroupIds'] << value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/add_job_flow_steps.rb b/lib/fog/aws/parsers/emr/add_job_flow_steps.rb new file mode 100644 index 000000000..6ca604236 --- /dev/null +++ b/lib/fog/aws/parsers/emr/add_job_flow_steps.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module EMR + class AddJobFlowSteps < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/describe_job_flows.rb b/lib/fog/aws/parsers/emr/describe_job_flows.rb new file mode 100644 index 000000000..20cf57a8f --- /dev/null +++ b/lib/fog/aws/parsers/emr/describe_job_flows.rb @@ -0,0 +1,137 @@ +module Fog + module Parsers + module AWS + module EMR + class DescribeJobFlows < Fog::Parsers::Base + def reset + @context = [] + @contexts = ['BootstrapActions', 'ExecutionStatusDetail', 'Instances', 'Steps', 'InstanceGroups', 'Args'] + + @response = { 'JobFlows' => [] } + @bootstrap_actions = {'ScriptBootstrapActionConfig' => {'Args' => []}} + @instance = { 'InstanceGroups' => [], 'Placement' => {}} + @step = { + 'ExecutionStatusDetail' => {}, + 'StepConfig' => { + 'HadoopJarStepConfig' => { + 'Args' => [], + 'Properties' => [] + } + } + } + @flow = {'Instances' => [], 'ExecutionStatusDetail' => {}, 'BootstrapActions' => [], 'Steps' => []} + @instance_group_detail = {} + @execution_status_detail = {} + end + + def start_element(name, attrs = []) + super + if @contexts.include?(name) + @context.push(name) + end + end + + def end_element(name) + if @context.last == 'BootstrapActions' + case name + when 'Name' + @bootstrap_actions[name] = value + when 'Path' + @bootstrap_actions['ScriptBootstrapActionConfig'][name] = value + when 'BootstrapActions' + @flow['BootstrapActions'] = @bootstrap_actions + @bootstrap_actions = {'ScriptBootstrapActionConfig' => {'Args' => []}} + end + end + + if @context.last == 'ExecutionStatusDetail' + case name + when 'CreationDateTime', 'EndDateTime', 'LastStateChangeReason', + 'ReadyDateTime', 'StartDateTime', 'State' + @execution_status_detail[name] = value + when 'ExecutionStatusDetail' + if @context.include?('Steps') + @step['ExecutionStatusDetail'] = @execution_status_detail + else + @flow['ExecutionStatusDetail'] = @execution_status_detail + end + @execution_status_detail = {} + end + end + + if @context.last == 'Instances' + case name + when 'AvailabilityZone' + @instance['Placement'][name] = value + when 'Ec2KeyName', 'HadoopVersion', 'InstanceCount', 'KeepJobFlowAliveWhenNoSteps', + 'MasterInstanceId', 'MasterInstanceType', 'MasterPublicDnsName', 'NormalizedInstanceHours', + 'SlaveInstanceType', 'TerminationProtected' + @instance[name] = value + when 'member' + @instance['InstanceGroups'] << @instance_group_detail + @instance_group_detail = {} + when 'Instances' + @flow['Instances'] = @instance + @instance = { 'InstanceGroups' => [], 'Placement' => {}} + end + end + + if @context.last == 'InstanceGroups' + case name + when 'member' + @instance['InstanceGroups'] << @instance_group_detail + @instance_group_detail = {} + else + @instance_group_detail[name] = value + end + end + + if @context.last == 'Args' + if name == 'member' + if @context.include?('Steps') + @step['StepConfig']['HadoopJarStepConfig']['Args'] << value.strip + else + @bootstrap_actions['ScriptBootstrapActionConfig']['Args'] << value + end + end + end + + if @context.last == 'Steps' + case name + when 'ActionOnFailure', 'Name' + @step[name] = value + when 'Jar', 'MainClass' + @step['StepConfig']['HadoopJarStepConfig'][name] = value + when 'member' + @flow['Steps'] << @step + @step = { + 'ExecutionStatusDetail' => {}, + 'StepConfig' => { + 'HadoopJarStepConfig' => { + 'Args' => [], + 'Properties' => [] + } + } + } + end + end + + if @context.empty? + case name + when 'AmiVersion', 'JobFlowId', 'LogUri', 'Name' + @flow[name] = value + when 'member' + @response['JobFlows'] << @flow + @flow = {'Instances' => [], 'ExecutionStatusDetail' => {}, 'BootstrapActions' => [], 'Steps' => []} + end + end + + if @context.last == name + @context.pop + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/modify_instance_groups.rb b/lib/fog/aws/parsers/emr/modify_instance_groups.rb new file mode 100644 index 000000000..af84e51bd --- /dev/null +++ b/lib/fog/aws/parsers/emr/modify_instance_groups.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module EMR + class ModifyInstanceGroups < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/run_job_flow.rb b/lib/fog/aws/parsers/emr/run_job_flow.rb new file mode 100644 index 000000000..e088eb63d --- /dev/null +++ b/lib/fog/aws/parsers/emr/run_job_flow.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module AWS + module EMR + class RunJobFlow < Fog::Parsers::Base + def end_element(name) + case name + when 'JobFlowId' + @response[name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/set_termination_protection.rb b/lib/fog/aws/parsers/emr/set_termination_protection.rb new file mode 100644 index 000000000..cc4374fb6 --- /dev/null +++ b/lib/fog/aws/parsers/emr/set_termination_protection.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module EMR + class SetTerminationProtection < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/emr/terminate_job_flows.rb b/lib/fog/aws/parsers/emr/terminate_job_flows.rb new file mode 100644 index 000000000..20c533e34 --- /dev/null +++ b/lib/fog/aws/parsers/emr/terminate_job_flows.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module EMR + class TerminateJobFlows < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/base_instance_profile.rb b/lib/fog/aws/parsers/iam/base_instance_profile.rb new file mode 100644 index 000000000..cb79aa2e1 --- /dev/null +++ b/lib/fog/aws/parsers/iam/base_instance_profile.rb @@ -0,0 +1,75 @@ +module Fog + module Parsers + module AWS + module IAM + class BaseInstanceProfile < Fog::Parsers::Base + def reset + super + @stack = [] + end + + def start_element(name,attrs = []) + super + case name + + when 'InstanceProfile' + @instance_profile = {'Roles' =>[]} + when 'InstanceProfiles' + @stack << 'InstanceProfiles' + when 'Roles' + @stack << 'Role' + when 'member' + case @stack.last + when 'InstanceProfiles' + @instance_profile = {'Roles' =>[]} + when 'Roles' + if @instance_profile + @role = {} + end + end + end + end + + def end_element(name) + if @instance_profile + case name + when 'Arn', 'Path' + if @role + @role[name] = value + else + @instance_profile[name] = value + end + when 'AssumeRolePolicyDocument', 'RoleId','RoleName' + @role[name] = value if @role + when 'CreateDate' + if @role + @role[name] = Time.parse(value) + else + @instance_profile[name] = Time.parse(value) + end + when 'member' + case @stack.last + when 'InstanceProfiles' + finished_instance_profile(@instance_profile) + @instance_profile = nil + when 'Roles' + if @instance_profile + @instance_profile['Roles'] << @role + @role = nil + end + end + when 'InstanceProfiles', 'Roles' + @stack.pop + when 'InstanceProfile' + finished_instance_profile(@instance_profile) + @instance_profile = nil + when 'InstanceProfileName', 'InstanceProfileId' + @instance_profile[name] = value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/basic.rb b/lib/fog/aws/parsers/iam/basic.rb new file mode 100644 index 000000000..43abee310 --- /dev/null +++ b/lib/fog/aws/parsers/iam/basic.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module AWS + module IAM + class Basic < Fog::Parsers::Base + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/create_access_key.rb b/lib/fog/aws/parsers/iam/create_access_key.rb new file mode 100644 index 000000000..d25b1a9e9 --- /dev/null +++ b/lib/fog/aws/parsers/iam/create_access_key.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module IAM + class CreateAccessKey < Fog::Parsers::Base + def reset + @response = { 'AccessKey' => {} } + end + + def end_element(name) + case name + when 'AccessKeyId', 'UserName', 'SecretAccessKey', 'Status' + @response['AccessKey'][name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/create_group.rb b/lib/fog/aws/parsers/iam/create_group.rb new file mode 100644 index 000000000..93c0bc708 --- /dev/null +++ b/lib/fog/aws/parsers/iam/create_group.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module IAM + class CreateGroup < Fog::Parsers::Base + def reset + @response = { 'Group' => {} } + end + + def end_element(name) + case name + when 'Arn', 'GroupId', 'GroupName', 'Path' + @response['Group'][name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/create_user.rb b/lib/fog/aws/parsers/iam/create_user.rb new file mode 100644 index 000000000..8a3200c89 --- /dev/null +++ b/lib/fog/aws/parsers/iam/create_user.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module IAM + class CreateUser < Fog::Parsers::Base + def reset + @response = { 'User' => {} } + end + + def end_element(name) + case name + when 'Arn', 'UserId', 'UserName', 'Path' + @response['User'][name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_account_password_policy.rb b/lib/fog/aws/parsers/iam/get_account_password_policy.rb new file mode 100644 index 000000000..d2267bb62 --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_account_password_policy.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module IAM + class GetAccountPolicyPolicy < Fog::Parsers::Base + def reset + @response = {'AccountPasswordPolicy' => {}} + end + + def end_element(name) + case name + when 'MinimumPasswordLength', 'MaxPasswordAge','PasswordReusePrevention' + #boolean values + @response['AccountPasswordPolicy'][name] = !!value + when 'RequireSymbols','RequireNumbers','RequireUppercaseCharacters','RequireLowercaseCharacters','AllowUsersToChangePassword','HardExpiry','ExpirePasswords' + #integer values + @response['AccountPasswordPolicy'][name] = value.to_i + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_account_summary.rb b/lib/fog/aws/parsers/iam/get_account_summary.rb new file mode 100644 index 000000000..dcaf02157 --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_account_summary.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module AWS + module IAM + class GetAccountSummary < Fog::Parsers::Base + def reset + super + @stack = [] + @response = {'Summary' => {}} + end + + def start_element(name, attrs = []) + super + case name + when 'SummaryMap' + @stack << name + end + end + + def end_element(name) + case name + when 'SummaryMap' + @stack.pop + when 'key' + if @stack.last == 'SummaryMap' + @key = value + end + when 'value' + if @stack.last == 'SummaryMap' + @response['Summary'][@key] = value.strip.to_i + end + when 'RequestId' + if @stack.empty? + @response['RequestId'] = value.strip + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_group.rb b/lib/fog/aws/parsers/iam/get_group.rb new file mode 100644 index 000000000..f6f6990ed --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_group.rb @@ -0,0 +1,52 @@ +module Fog + module Parsers + module AWS + module IAM + class GetGroup < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_GetGroup.html + + def reset + @user = {} + @response = { 'Group' => {}, 'Users' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Group' + @in_group = true + when 'Users' + @in_users = true + end + end + + def end_element(name) + case name + when 'Arn', 'Path' + if @in_group + @response['Group'][name] = value + elsif @in_users + @user[name] = value + end + when 'Group' + @in_group = false + when 'GroupName', 'GroupId' + @response['Group'][name] = value + when 'Users' + @in_users = false + when 'UserId', 'UserName' + @user[name] = value + when 'member' + @response['Users'] << @user + @user = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_group_policy.rb b/lib/fog/aws/parsers/iam/get_group_policy.rb new file mode 100644 index 000000000..5c8ca9946 --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_group_policy.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module AWS + module IAM + class GetGroupPolicy < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetGroupPolicy.html + + def reset + @response = { 'Policy' => {} } + end + + def end_element(name) + case name + when 'GroupName', 'PolicyName' + @response[name] = value + when 'PolicyDocument' + @response['Policy'][name] = if decoded_string = URI.decode(value) + Fog::JSON.decode(decoded_string) rescue value + else + value + end + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_role_policy.rb b/lib/fog/aws/parsers/iam/get_role_policy.rb new file mode 100644 index 000000000..124cc467c --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_role_policy.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module IAM + class GetRolePolicy < Fog::Parsers::Base + def reset + @response = {'Policy' => {}} + end + + def end_element(name) + case name + when 'RoleName', 'PolicyName' + @response['Policy'][name] = value + when 'PolicyDocument' + @response['Policy'][name] = if decoded_string = URI.decode(value) + Fog::JSON.decode(decoded_string) rescue value + else + value + end + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_user.rb b/lib/fog/aws/parsers/iam/get_user.rb new file mode 100644 index 000000000..ec737d921 --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_user.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module IAM + class GetUser < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetUser.html + + def reset + @response = { 'User' => {} } + end + + def end_element(name) + case name + when 'Arn', 'UserId', 'UserName', 'Path' + @response['User'][name] = value + when 'CreateDate' + @response['User'][name] = Time.parse(value) + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/get_user_policy.rb b/lib/fog/aws/parsers/iam/get_user_policy.rb new file mode 100644 index 000000000..af26e7b4a --- /dev/null +++ b/lib/fog/aws/parsers/iam/get_user_policy.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module AWS + module IAM + class GetUserPolicy < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetUserPolicy.html + + def reset + @response = { 'Policy' => {} } + end + + def end_element(name) + case name + when 'UserName', 'PolicyName' + @response['Policy'][name] = value + when 'PolicyDocument' + @response['Policy'][name] = if decoded_string = URI.decode(value) + Fog::JSON.decode(decoded_string) rescue value + else + value + end + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/instance_profile.rb b/lib/fog/aws/parsers/iam/instance_profile.rb new file mode 100644 index 000000000..4b9b4a629 --- /dev/null +++ b/lib/fog/aws/parsers/iam/instance_profile.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module IAM + require 'fog/aws/parsers/iam/base_instance_profile' + + class InstanceProfile < Fog::Parsers::AWS::IAM::BaseInstanceProfile + def reset + super + @response = {} + end + + def finished_instance_profile(profile) + @response['InstanceProfile'] = profile + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + super + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_access_keys.rb b/lib/fog/aws/parsers/iam/list_access_keys.rb new file mode 100644 index 000000000..fb141b3cf --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_access_keys.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module IAM + class ListAccessKeys < Fog::Parsers::Base + def reset + @access_key = {} + @response = { 'AccessKeys' => [] } + end + + def end_element(name) + case name + when 'AccessKeyId', 'Status', 'Username' + @access_key[name] = value + when 'member' + @response['AccessKeys'] << @access_key + @access_key = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_account_aliases.rb b/lib/fog/aws/parsers/iam/list_account_aliases.rb new file mode 100644 index 000000000..55a805870 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_account_aliases.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module IAM + class ListAccountAliases < Fog::Parsers::Base + def reset + @response = { 'AccountAliases' => [] } + end + + def end_element(name) + case name + when 'member' + @response['AccountAliases'] << @value + when 'IsTruncated' + response[name] = (@value == 'true') + when 'Marker', 'RequestId' + response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_groups.rb b/lib/fog/aws/parsers/iam/list_groups.rb new file mode 100644 index 000000000..b44bde988 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_groups.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module IAM + class ListGroups < Fog::Parsers::Base + def reset + @group = {} + @response = { 'Groups' => [] } + end + + def end_element(name) + case name + when 'Arn', 'GroupId', 'GroupName', 'Path' + @group[name] = value + when 'member' + @response['Groups'] << @group + @group = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_groups_for_user.rb b/lib/fog/aws/parsers/iam/list_groups_for_user.rb new file mode 100644 index 000000000..645083aba --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_groups_for_user.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module IAM + class ListGroupsForUser < Fog::Parsers::Base + def reset + @group_for_user = {} + @response = { 'GroupsForUser' => [] } + end + + def end_element(name) + case name + when 'Path', 'GroupName', 'GroupId', 'Arn' + @group_for_user[name] = value + when 'member' + @response['GroupsForUser'] << @group_for_user + @group_for_user = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_instance_profiles.rb b/lib/fog/aws/parsers/iam/list_instance_profiles.rb new file mode 100644 index 000000000..4d0f24dad --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_instance_profiles.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module IAM + require 'fog/aws/parsers/iam/base_instance_profile' + class ListInstanceProfiles < Fog::Parsers::AWS::IAM::BaseInstanceProfile + def reset + super + @response = {'InstanceProfiles' => []} + end + + def finished_instance_profile(profile) + @response['InstanceProfiles'] << profile + end + + def end_element(name) + case name + when 'RequestId', 'Marker' + @response[name] = value + when 'IsTruncated' + @response[name] = (value == 'true') + end + super + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_mfa_devices.rb b/lib/fog/aws/parsers/iam/list_mfa_devices.rb new file mode 100644 index 000000000..08c3592a0 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_mfa_devices.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module AWS + module IAM + class ListMFADevices < Fog::Parsers::Base + def reset + @mfa_device = {} + @response = { 'MFADevices' => [] } + end + + def end_element(name) + case name + when 'SerialNumber', 'UserName' + @mfa_device[name] = value + when 'EnableDate' + @mfa_device[name] = Time.parse(value) + when 'member' + @response['MFADevices'] << @mfa_device + @mfa_device = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_policies.rb b/lib/fog/aws/parsers/iam/list_policies.rb new file mode 100644 index 000000000..13976a14f --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_policies.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module IAM + class ListPolicies < Fog::Parsers::Base + def reset + @response = { 'PolicyNames' => [] } + end + + def end_element(name) + case name + when 'member' + @response['PolicyNames'] << value + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_roles.rb b/lib/fog/aws/parsers/iam/list_roles.rb new file mode 100644 index 000000000..4a8733a10 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_roles.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module IAM + require 'fog/aws/parsers/iam/role_parser' + class ListRoles < Fog::Parsers::AWS::IAM::RoleParser + def reset + super + @response = { 'Roles' => [] } + end + + def finished_role(role) + @response['Roles'] << role + end + + def end_element(name) + case name + when 'RequestId', 'Marker' + @response[name] = value + when 'IsTruncated' + @response[name] = (value == 'true') + end + super + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_server_certificates.rb b/lib/fog/aws/parsers/iam/list_server_certificates.rb new file mode 100644 index 000000000..1810a78c0 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_server_certificates.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module IAM + class ListServerCertificates < Fog::Parsers::Base + def reset + @response = { 'Certificates' => [] } + reset_certificate + end + + def reset_certificate + @certificate = {} + end + + def end_element(name) + case name + when 'Arn', 'Path', 'ServerCertificateId', 'ServerCertificateName' + @certificate[name] = value + when 'UploadDate' + @certificate[name] = Time.parse(value) + when 'member' + @response['Certificates'] << @certificate + reset_certificate + when 'IsTrunctated' + @response[name] = !!value + when 'Marker' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_signing_certificates.rb b/lib/fog/aws/parsers/iam/list_signing_certificates.rb new file mode 100644 index 000000000..2d3e80d43 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_signing_certificates.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module IAM + class ListSigningCertificates < Fog::Parsers::Base + def reset + @signing_certificate = {} + @response = { 'SigningCertificates' => [] } + end + + def end_element(name) + case name + when 'UserName', 'CertificateId', 'CertificateBody', 'Status' + @signing_certificate[name] = value + when 'member' + @response['SigningCertificates'] << @signing_certificate + @signing_certificate = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/list_users.rb b/lib/fog/aws/parsers/iam/list_users.rb new file mode 100644 index 000000000..ee51adea9 --- /dev/null +++ b/lib/fog/aws/parsers/iam/list_users.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module AWS + module IAM + class ListUsers < Fog::Parsers::Base + def reset + @user = {} + @response = { 'Users' => [] } + end + + def end_element(name) + case name + when 'Arn', 'UserId', 'UserName', 'Path' + @user[name] = value + when 'CreateDate' + @user[name] = Time.parse(value) + when 'member' + @response['Users'] << @user + @user = {} + when 'IsTruncated' + response[name] = (value == 'true') + when 'Marker', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/login_profile.rb b/lib/fog/aws/parsers/iam/login_profile.rb new file mode 100644 index 000000000..210bda312 --- /dev/null +++ b/lib/fog/aws/parsers/iam/login_profile.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module IAM + class LoginProfile < Fog::Parsers::Base + def reset + @response = { 'LoginProfile' => {} } + end + + def end_element(name) + case name + when 'UserName' + @response['LoginProfile']['UserName'] = value + when 'CreateDate' + @response['LoginProfile']['CreateDate'] = Time.parse(value) + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/role_parser.rb b/lib/fog/aws/parsers/iam/role_parser.rb new file mode 100644 index 000000000..3660ec2e9 --- /dev/null +++ b/lib/fog/aws/parsers/iam/role_parser.rb @@ -0,0 +1,49 @@ +module Fog + module Parsers + module AWS + module IAM + class RoleParser < Fog::Parsers::Base + def reset + @role = {} + @stack = [] + end + + def start_element(name,attrs = []) + case name + when 'Roles' + @stack << name + when 'Role' + @role = {} + when 'member' + if @stack.last == 'Roles' + @role = {} + end + end + super + end + + def end_element(name) + case name + when 'Arn', 'AssumeRolePolicyDocument', 'Path', 'RoleId','RoleName' + @role[name] = value if @role + when 'CreateDate' + @role[name] = Time.parse(value) if @role + when 'Role' + finished_role(@role) + @role = nil + when 'Roles' + if @stack.last == 'Roles' + @stack.pop + end + when 'member' + if @stack.last == 'Roles' + finished_role(@role) + @role = nil + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/single_role.rb b/lib/fog/aws/parsers/iam/single_role.rb new file mode 100644 index 000000000..4ea4ca015 --- /dev/null +++ b/lib/fog/aws/parsers/iam/single_role.rb @@ -0,0 +1,27 @@ +module Fog + module Parsers + module AWS + module IAM + require 'fog/aws/parsers/iam/role_parser' + class SingleRole < Fog::Parsers::AWS::IAM::RoleParser + def reset + super + @response = { 'Role' => {} } + end + + def finished_role(role) + @response['Role'] = role + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = value + end + super + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/update_group.rb b/lib/fog/aws/parsers/iam/update_group.rb new file mode 100644 index 000000000..fa84f57f0 --- /dev/null +++ b/lib/fog/aws/parsers/iam/update_group.rb @@ -0,0 +1,23 @@ +module Fog + module Parsers + module AWS + module IAM + class UpdateGroup < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UpdateGroup.html + def reset + @response = { 'Group' => {} } + end + + def end_element(name) + case name + when 'Arn', 'GroupId', 'GroupName', 'Path' + @response['Group'][name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/update_user.rb b/lib/fog/aws/parsers/iam/update_user.rb new file mode 100644 index 000000000..bbe889cd3 --- /dev/null +++ b/lib/fog/aws/parsers/iam/update_user.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module IAM + class UpdateUser < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UpdateUser.html + + def reset + @response = { 'User' => {} } + end + + def end_element(name) + case name + when 'Arn', 'UserId', 'UserName', 'Path' + @response['User'][name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/upload_server_certificate.rb b/lib/fog/aws/parsers/iam/upload_server_certificate.rb new file mode 100644 index 000000000..8c771594e --- /dev/null +++ b/lib/fog/aws/parsers/iam/upload_server_certificate.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module IAM + class UploadServerCertificate < Fog::Parsers::Base + def reset + @response = { 'Certificate' => {} } + end + + def end_element(name) + case name + when 'Arn', 'Path', 'ServerCertificateId', 'ServerCertificateName', 'CertificateBody', 'CertificateChain' + @response['Certificate'][name] = value + when 'UploadDate' + @response['Certificate'][name] = Time.parse(value) + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/iam/upload_signing_certificate.rb b/lib/fog/aws/parsers/iam/upload_signing_certificate.rb new file mode 100644 index 000000000..2bc568497 --- /dev/null +++ b/lib/fog/aws/parsers/iam/upload_signing_certificate.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module IAM + class UploadSigningCertificate < Fog::Parsers::Base + def reset + @response = { 'Certificate' => {} } + end + + def end_element(name) + case name + when 'CertificateId', 'UserName', 'CertificateBody', 'Status' + @response['Certificate'][name] = value + when 'RequestId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/authorize_db_security_group_ingress.rb b/lib/fog/aws/parsers/rds/authorize_db_security_group_ingress.rb new file mode 100644 index 000000000..8248051ae --- /dev/null +++ b/lib/fog/aws/parsers/rds/authorize_db_security_group_ingress.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/security_group_parser' + + class AuthorizeDBSecurityGroupIngress < Fog::Parsers::AWS::RDS::SecurityGroupParser + def reset + @response = { 'AuthorizeDBSecurityGroupIngressResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSecurityGroup' then + @response['AuthorizeDBSecurityGroupIngressResult']['DBSecurityGroup'] = @security_group + @security_group = fresh_security_group + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/base.rb b/lib/fog/aws/parsers/rds/base.rb new file mode 100644 index 000000000..de9ad6583 --- /dev/null +++ b/lib/fog/aws/parsers/rds/base.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module AWS + module RDS + # Base parser for ResponseMetadata, RequestId + class Base < Fog::Parsers::Base + def reset + super + @response = { 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_db_instance.rb b/lib/fog/aws/parsers/rds/create_db_instance.rb new file mode 100644 index 000000000..7bdfa72ca --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_db_instance.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class CreateDBInstance < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'CreateDBInstanceResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['CreateDBInstanceResult']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_db_instance_read_replica.rb b/lib/fog/aws/parsers/rds/create_db_instance_read_replica.rb new file mode 100644 index 000000000..b19b3a7ec --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_db_instance_read_replica.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class CreateDBInstanceReadReplica < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'CreateDBInstanceReadReplicaResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['CreateDBInstanceReadReplicaResult']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_db_parameter_group.rb b/lib/fog/aws/parsers/rds/create_db_parameter_group.rb new file mode 100644 index 000000000..0b057081f --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_db_parameter_group.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module RDS + class CreateDbParameterGroup < Fog::Parsers::Base + def reset + @response = { 'CreateDBParameterGroupResult' => {}, 'ResponseMetadata' => {} } + @db_parameter_group = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBParameterGroupFamily' + @db_parameter_group['DBParameterGroupFamily'] = value + when 'Description' + @db_parameter_group['Description'] = value + when 'DBParameterGroupName' + @db_parameter_group['DBParameterGroupName'] = value + when 'DBParameterGroup' + @response['CreateDBParameterGroupResult']['DBParameterGroup']= @db_parameter_group + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_db_security_group.rb b/lib/fog/aws/parsers/rds/create_db_security_group.rb new file mode 100644 index 000000000..f35c1f2c2 --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_db_security_group.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/security_group_parser' + + class CreateDBSecurityGroup < Fog::Parsers::AWS::RDS::SecurityGroupParser + def reset + @response = { 'CreateDBSecurityGroupResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSecurityGroup' then + @response['CreateDBSecurityGroupResult']['DBSecurityGroup'] = @security_group + @security_group = fresh_security_group + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_db_snapshot.rb b/lib/fog/aws/parsers/rds/create_db_snapshot.rb new file mode 100644 index 000000000..d24fc17f9 --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_db_snapshot.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/snapshot_parser' + + class CreateDBSnapshot < Fog::Parsers::AWS::RDS::SnapshotParser + def reset + @response = { 'CreateDBSnapshotResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSnapshot' then + @response['CreateDBSnapshotResult']['DBSnapshot'] = @db_snapshot + @db_snapshot = fresh_snapshot + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_db_subnet_group.rb b/lib/fog/aws/parsers/rds/create_db_subnet_group.rb new file mode 100644 index 000000000..6cce8886d --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_db_subnet_group.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/subnet_group_parser' + + class CreateDBSubnetGroup < Fog::Parsers::AWS::RDS::SubnetGroupParser + def reset + @response = { 'CreateDBSubnetGroupResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSubnetGroup' then + @response['CreateDBSubnetGroupResult']['DBSubnetGroup'] = @db_subnet_group + @db_subnet_group = fresh_subnet_group + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/create_event_subscription.rb b/lib/fog/aws/parsers/rds/create_event_subscription.rb new file mode 100644 index 000000000..749ec9489 --- /dev/null +++ b/lib/fog/aws/parsers/rds/create_event_subscription.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/event_subscription_parser' + + class CreateEventSubscription < Fog::Parsers::AWS::RDS::EventSubscriptionParser + def reset + @response = { 'CreateEventSubscriptionResult' => {}, 'ResponseMetadata' => {} } + @event_subscription = {} + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'EventSubscription' + @response['CreateEventSubscriptionResult']['EventSubscription'] = @event_subscription + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/db_engine_version_parser.rb b/lib/fog/aws/parsers/rds/db_engine_version_parser.rb new file mode 100644 index 000000000..1826b805e --- /dev/null +++ b/lib/fog/aws/parsers/rds/db_engine_version_parser.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + class DBEngineVersionParser < Fog::Parsers::Base + def reset + @db_engine_version = fresh_engine_version + end + + def fresh_engine_version + {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBEngineDescription' then @db_engine_version['DBEngineDescription'] = @value + when 'DBEngineVersionDescription' then @db_engine_version['DBEngineVersionDescription'] = @value + when 'DBParameterGroupFamily' then @db_engine_version['DBParameterGroupFamily'] = @value + when 'DBEngineVersionIdentifier' then @db_engine_version['DBEngineVersionIdentifier'] = @value + when 'Engine' then @db_engine_version['Engine'] = @value + when 'EngineVersion' then @db_engine_version['EngineVersion'] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/db_parser.rb b/lib/fog/aws/parsers/rds/db_parser.rb new file mode 100644 index 000000000..1679615c0 --- /dev/null +++ b/lib/fog/aws/parsers/rds/db_parser.rb @@ -0,0 +1,136 @@ +module Fog + module Parsers + module AWS + module RDS + class DbParser < Fog::Parsers::Base + def reset + @db_instance = fresh_instance + end + + def fresh_instance + {'PendingModifiedValues' => [], 'DBSecurityGroups' => [], 'ReadReplicaDBInstanceIdentifiers' => [], 'Endpoint' => {}} + end + + def start_element(name, attrs = []) + super + case name + when 'PendingModifiedValues' + @in_pending_modified_values = true + @pending_modified_values = {} + when 'DBSecurityGroups' + @in_db_security_groups = true + @db_security_groups = [] + when 'DBSecurityGroup' + @db_security_group = {} + when 'Endpoint' + @in_endpoint = true + @endpoint = {} + when 'DBParameterGroup' + @db_parameter_group = {} + when 'DBParameterGroups' + @in_db_parameter_groups = true + @db_parameter_groups = [] + when 'VpcSecurityGroupMembership' + @vpc_security_group = {} + when 'VpcSecurityGroups' + @in_vpc_security_groups = true + @vpc_security_groups = [] + end + end + + def end_element(name) + case name + + when 'LatestRestorableTime', 'InstanceCreateTime' + @db_instance[name] = Time.parse value + when 'Engine', 'DBInstanceStatus', 'DBInstanceIdentifier', + 'PreferredBackupWindow', 'PreferredMaintenanceWindow', + 'AvailabilityZone', 'MasterUsername', 'DBName', 'LicenseModel', + 'DBSubnetGroupName', 'StorageType' + @db_instance[name] = value + when 'MultiAZ', 'AutoMinorVersionUpgrade', 'PubliclyAccessible' + if value == 'false' + @db_instance[name] = false + else + @db_instance[name] = true + end + when 'DBParameterGroups' + @in_db_parameter_groups = false + @db_instance['DBParameterGroups'] = @db_parameter_groups + when 'DBParameterGroup' + @db_parameter_groups << @db_parameter_group + @db_parameter_group = {} + when 'ParameterApplyStatus', 'DBParameterGroupName' + if @in_db_parameter_groups + @db_parameter_group[name] = value + end + + when 'BackupRetentionPeriod' + if @in_pending_modified_values + @pending_modified_values[name] = value.to_i + else + @db_instance[name] = value.to_i + end + when 'DBInstanceClass', 'EngineVersion', 'MasterUserPassword', + 'MultiAZ', 'Iops', 'AllocatedStorage' + if @in_pending_modified_values + @pending_modified_values[name] = value + else + @db_instance[name] = value + end + when 'DBSecurityGroups' + @in_db_security_groups = false + @db_instance['DBSecurityGroups'] = @db_security_groups + when 'DBSecurityGroupName' + @db_security_group[name]=value + when 'DBSecurityGroup' + @db_security_groups << @db_security_group + @db_security_group = {} + + when 'VpcSecurityGroups' + @in_vpc_security_groups = false + @db_instance['VpcSecurityGroups'] = @vpc_security_groups + when 'VpcSecurityGroupMembership' + @vpc_security_groups << @vpc_security_group + @vpc_security_group = {} + when 'VpcSecurityGroupId' + @vpc_security_group[name] = value + + when 'Status' + # Unfortunately, status is used in VpcSecurityGroupMemebership and + # DBSecurityGroups + if @in_db_security_groups + @db_security_group[name]=value + end + if @in_vpc_security_groups + @vpc_security_group[name] = value + end + + when 'Address' + @endpoint[name] = value + when 'Port' + if @in_pending_modified_values + @pending_modified_values[name] = value.to_i + elsif @in_endpoint + @endpoint[name] = value.to_i + end + + when 'PendingModifiedValues' + @in_pending_modified_values = false + @db_instance['PendingModifiedValues'] = @pending_modified_values + when 'Endpoint' + @in_endpoint = false + @db_instance['Endpoint'] = @endpoint + when 'ReadReplicaDBInstanceIdentifier' + @db_instance['ReadReplicaDBInstanceIdentifiers'] << value + when 'ReadReplicaSourceDBInstanceIdentifier' + @db_instance['ReadReplicaSourceDBInstanceIdentifier'] = value + when 'DBInstance' + @db_instance = fresh_instance + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/delete_db_instance.rb b/lib/fog/aws/parsers/rds/delete_db_instance.rb new file mode 100644 index 000000000..98b9989e3 --- /dev/null +++ b/lib/fog/aws/parsers/rds/delete_db_instance.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class DeleteDBInstance < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'DeleteDBInstanceResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + + when 'DBInstance' + @response['DeleteDBInstanceResult']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/delete_db_parameter_group.rb b/lib/fog/aws/parsers/rds/delete_db_parameter_group.rb new file mode 100644 index 000000000..8056bbcba --- /dev/null +++ b/lib/fog/aws/parsers/rds/delete_db_parameter_group.rb @@ -0,0 +1,25 @@ +module Fog + module Parsers + module AWS + module RDS + class DeleteDbParameterGroup < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + @db_parameter_group = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/delete_db_security_group.rb b/lib/fog/aws/parsers/rds/delete_db_security_group.rb new file mode 100644 index 000000000..79282657c --- /dev/null +++ b/lib/fog/aws/parsers/rds/delete_db_security_group.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/snapshot_parser' + + class DeleteDBSecurityGroup < Fog::Parsers::AWS::RDS::SnapshotParser + def reset + @response = { 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/delete_db_snapshot.rb b/lib/fog/aws/parsers/rds/delete_db_snapshot.rb new file mode 100644 index 000000000..6250daab8 --- /dev/null +++ b/lib/fog/aws/parsers/rds/delete_db_snapshot.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/snapshot_parser' + + class DeleteDBSnapshot < Fog::Parsers::AWS::RDS::SnapshotParser + def reset + @response = { 'DeleteDBSnapshotResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + when 'DBSnapshot' + @response['DeleteDBSnapshotResult']['DBSnapshot'] = @db_snapshot + @db_snapshot = fresh_snapshot + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/delete_db_subnet_group.rb b/lib/fog/aws/parsers/rds/delete_db_subnet_group.rb new file mode 100644 index 000000000..923c65e0a --- /dev/null +++ b/lib/fog/aws/parsers/rds/delete_db_subnet_group.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/subnet_group_parser' + + class DeleteDBSubnetGroup < Fog::Parsers::AWS::RDS::SubnetGroupParser + def reset + @response = { 'DeleteDBSubnetGroupResponse' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/delete_event_subscription.rb b/lib/fog/aws/parsers/rds/delete_event_subscription.rb new file mode 100644 index 000000000..d7acf1705 --- /dev/null +++ b/lib/fog/aws/parsers/rds/delete_event_subscription.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/snapshot_parser' + + class DeleteEventSubscription < Fog::Parsers::AWS::RDS::SnapshotParser + def reset + @response = { 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs=[]) + super + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_engine_versions.rb b/lib/fog/aws/parsers/rds/describe_db_engine_versions.rb new file mode 100644 index 000000000..452d1b5aa --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_engine_versions.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_engine_version_parser' + + class DescribeDBEngineVersions < Fog::Parsers::AWS::RDS::DBEngineVersionParser + def reset + @response = { 'DescribeDBEngineVersionsResult' => {'DBEngineVersions' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBEngineVersion' then + @response['DescribeDBEngineVersionsResult']['DBEngineVersions'] << @db_engine_version + @db_engine_version = fresh_engine_version + when 'Marker' + @response['DescribeDBEngineVersionsResult']['Marker'] = @value + when 'RequestId' + @response['ResponseMetadata'][name] = @value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_instances.rb b/lib/fog/aws/parsers/rds/describe_db_instances.rb new file mode 100644 index 000000000..d20c08acc --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_instances.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class DescribeDBInstances < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'DescribeDBInstancesResult' => {'DBInstances' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['DescribeDBInstancesResult']['DBInstances'] << @db_instance + @db_instance = fresh_instance + when 'Marker' + @response['DescribeDBInstancesResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_log_files.rb b/lib/fog/aws/parsers/rds/describe_db_log_files.rb new file mode 100644 index 000000000..bdbcadcc1 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_log_files.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module AWS + module RDS + class DescribeDBLogFiles < Fog::Parsers::Base + attr_reader :rds_id + + def initialize(rds_id) + @rds_id = rds_id + super() + end + + def reset + @response = { 'DescribeDBLogFilesResult' => {'DBLogFiles' => []}, 'ResponseMetadata' => {} } + fresh_log_file + end + + def fresh_log_file + @db_log_file = {'DBInstanceIdentifier' => @rds_id} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'LastWritten' then @db_log_file[name] = Time.at(value.to_i / 1000) + when 'LogFileName' then @db_log_file[name] = value + when 'Size' then @db_log_file[name] = value.to_i + when 'DescribeDBLogFilesDetails' + @response['DescribeDBLogFilesResult']['DBLogFiles'] << @db_log_file + fresh_log_file + when 'Marker' then @response['DescribeDBLogFilesResult'][name] = value + when 'RequestId' then @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_parameter_groups.rb b/lib/fog/aws/parsers/rds/describe_db_parameter_groups.rb new file mode 100644 index 000000000..f724cb740 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_parameter_groups.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module RDS + class DescribeDBParameterGroups < Fog::Parsers::Base + def reset + @response = { 'DescribeDBParameterGroupsResult' => {'DBParameterGroups' => []}, 'ResponseMetadata' => {} } + @db_parameter_group = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBParameterGroupFamily' then @db_parameter_group['DBParameterGroupFamily'] = value + when 'Description' then @db_parameter_group['Description'] = value + when 'DBParameterGroupName' then @db_parameter_group['DBParameterGroupName'] = value + when 'DBParameterGroup' then + @response['DescribeDBParameterGroupsResult']['DBParameterGroups'] << @db_parameter_group + @db_parameter_group = {} + when 'Marker' + @response['DescribeDBParameterGroupsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_parameters.rb b/lib/fog/aws/parsers/rds/describe_db_parameters.rb new file mode 100644 index 000000000..c74b179cd --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_parameters.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module AWS + module RDS + class DescribeDBParameters < Fog::Parsers::Base + def reset + @response = { 'DescribeDBParametersResult' =>{}, 'ResponseMetadata' => {} } + @parameter = {} + @parameters = [] + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'ParameterValue' then @parameter['ParameterValue'] = value + when 'DataType' then @parameter['DataType'] = value + when 'AllowedValues' then @parameter['AllowedValues'] = value + when 'Source' then @parameter['Source'] = value + when 'IsModifiable' then + @parameter['IsModifiable'] = value == 'true' ? true : false + when 'Description' then @parameter['Description'] = value + when 'ApplyType' then @parameter['ApplyType'] = value + when 'ParameterName' then @parameter['ParameterName'] = value + when 'Parameter' + @parameters << @parameter + @parameter = {} + when 'Marker' + @response['DescribeDBParametersResult']['Marker'] = value + when 'Parameters' + @response['DescribeDBParametersResult']['Parameters'] = @parameters + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_reserved_instances.rb b/lib/fog/aws/parsers/rds/describe_db_reserved_instances.rb new file mode 100644 index 000000000..9cf07cc4a --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_reserved_instances.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module AWS + module RDS + class DescribeDBReservedInstances < Fog::Parsers::Base + def reset + @reserved_instance = {} + @response = { 'ReservedDBInstances' => [] } + end + + def end_element(name) + case name + when 'ReservedDBInstanceId', 'ReservedDBInstancesOfferingId', 'DBInstanceClass', 'ProductDescription', 'State' + @reserved_instance[name] = @value + when 'Duration', 'DBInstanceCount' + @reserved_instance[name] = @value.to_i + when 'FixedPrice', 'UsagePrice' + @reserved_instance[name] = @value.to_f + when 'ReservedDBInstance' + @response['ReservedDBInstances'] << @reserved_instance + @reserved_instance = {} + when 'Marker' + @response[name] = @value + when 'MultiAZ' + if @value == 'false' + @reserved_instance[name] = false + else + @reserved_instance[name] = true + end + when 'StartTime' + @reserved_instance[name] = Time.parse(@value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_security_groups.rb b/lib/fog/aws/parsers/rds/describe_db_security_groups.rb new file mode 100644 index 000000000..3e2acba09 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_security_groups.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/security_group_parser' + + class DescribeDBSecurityGroups < Fog::Parsers::AWS::RDS::SecurityGroupParser + def reset + @response = { 'DescribeDBSecurityGroupsResult' => {'DBSecurityGroups' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSecurityGroup' then + @response['DescribeDBSecurityGroupsResult']['DBSecurityGroups'] << @security_group + @security_group = fresh_security_group + when 'Marker' + @response['DescribeDBSecurityGroupsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_snapshots.rb b/lib/fog/aws/parsers/rds/describe_db_snapshots.rb new file mode 100644 index 000000000..fe89f6185 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_snapshots.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/snapshot_parser' + + class DescribeDBSnapshots < Fog::Parsers::AWS::RDS::SnapshotParser + def reset + @response = { 'DescribeDBSnapshotsResult' => {'DBSnapshots' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSnapshot' then + @response['DescribeDBSnapshotsResult']['DBSnapshots'] << @db_snapshot + @db_snapshot = fresh_snapshot + when 'Marker' + @response['DescribeDBSnapshotsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_db_subnet_groups.rb b/lib/fog/aws/parsers/rds/describe_db_subnet_groups.rb new file mode 100644 index 000000000..57c048fdf --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_db_subnet_groups.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/subnet_group_parser' + + class DescribeDBSubnetGroups < Fog::Parsers::AWS::RDS::SubnetGroupParser + def reset + @response = { 'DescribeDBSubnetGroupsResult' => {'DBSubnetGroups' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSubnetGroup' + @response['DescribeDBSubnetGroupsResult']['DBSubnetGroups'] << @db_subnet_group + @db_subnet_group = fresh_subnet_group + when 'Marker' + @response['DescribeDBSubnetGroupsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_event_subscriptions.rb b/lib/fog/aws/parsers/rds/describe_event_subscriptions.rb new file mode 100644 index 000000000..923b99d79 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_event_subscriptions.rb @@ -0,0 +1,34 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/event_subscription_parser' + + class DescribeEventSubscriptions < Fog::Parsers::AWS::RDS::EventSubscriptionParser + def reset + @response = { 'DescribeEventSubscriptionsResult' => { 'EventSubscriptionsList' => []}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'EventSubscription' + @response['DescribeEventSubscriptionsResult']['EventSubscriptionsList'] << @event_subscription + @event_subscription = fresh_event_subscription + when 'Marker' + @response['DescribeEventSubscriptionsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb new file mode 100644 index 000000000..cb0f78a56 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb @@ -0,0 +1,45 @@ +module Fog + module Parsers + module AWS + module RDS + class DescribeOrderableDBInstanceOptions < Fog::Parsers::Base + def reset + @response = { 'DescribeOrderableDBInstanceOptionsResult' => {'OrderableDBInstanceOptions' => []}, 'ResponseMetadata' => {} } + @db_instance_option = {} + @db_instance_options = [] + end + + def start_element(name, attrs = []) + case name + when 'AvailabilityZones' then @availability_zones = [] + when 'AvailabilityZone' then @availability_zone = {} + end + super + end + + def end_element(name) + case name + when 'MultiAZCapable', 'ReadReplicaCapable', 'Vpc' then @db_instance_option[name] = to_boolean(value) + when 'Engine', 'LicenseModel', 'EngineVersion', 'DBInstanceClass' then @db_instance_option[name] = value + when 'AvailabilityZones' then @db_instance_option[name] = @availability_zones + when 'AvailabilityZone' then @availability_zones << @availability_zone unless @availability_zone.empty? + when 'Name' then @availability_zone[name] = value + when 'ProvisionedIopsCapable' then @availability_zone[name] = to_boolean(value) + when 'OrderableDBInstanceOption' + @db_instance_options << @db_instance_option + @db_instance_option = {} + when 'OrderableDBInstanceOptions' + @response['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'] = @db_instance_options + when 'Marker' then @response['DescribeOrderableDBInstanceOptionsResult'][name] = value + when 'RequestId' then @response['ResponseMetadata'][name] = value + end + end + + def to_boolean(v) + (v =~ /\A\s*(true|yes|1|y)\s*$/i) == 0 + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/download_db_logfile_portion.rb b/lib/fog/aws/parsers/rds/download_db_logfile_portion.rb new file mode 100644 index 000000000..8b1d97ffb --- /dev/null +++ b/lib/fog/aws/parsers/rds/download_db_logfile_portion.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module RDS + class DownloadDBLogFilePortion < Fog::Parsers::Base + def reset + @response = { 'DownloadDBLogFilePortionResult' => {}, 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + key = (name == 'RequestId') ? 'ResponseMetadata' : 'DownloadDBLogFilePortionResult' + @response[key][name] = value + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/event_list.rb b/lib/fog/aws/parsers/rds/event_list.rb new file mode 100644 index 000000000..35753e9e0 --- /dev/null +++ b/lib/fog/aws/parsers/rds/event_list.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/base' + + class EventListParser < Base + def reset + super + @response['Events'] = [] + end + + def start_element(name, attrs = []) + super + case name + when 'Event'; then @event = {} + end + end + + def end_element(name) + case name + when 'Date' + @event[name] = DateTime.parse(value.strip) + when 'Message', 'SourceIdentifier', 'SourceType' + @event[name] = value ? value.strip : name + when 'Event' + @response['Events'] << @event unless @event.empty? + when 'IsTruncated', 'Marker', 'NextMarker' + @response[name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/event_subscription_parser.rb b/lib/fog/aws/parsers/rds/event_subscription_parser.rb new file mode 100644 index 000000000..e6786255b --- /dev/null +++ b/lib/fog/aws/parsers/rds/event_subscription_parser.rb @@ -0,0 +1,37 @@ +module Fog + module Parsers + module AWS + module RDS + class EventSubscriptionParser < Fog::Parsers::Base + def reset + @event_subscription = fresh_event_subscription + end + + def fresh_event_subscription + {'EventCategories'=> []} + end + + def start_element(name, attrs = []) + super + case name + when 'EventCategoriesList' + @in_event_categories_list = true + end + end + + def end_element(name) + case name + when 'EventCategory' + @event_subscription['EventCategories'] << value + @in_event_categories_list = false + when 'SubscriptionCreationTime' + @event_subscription[name] = Time.parse(value) + when 'Enabled', 'CustomerAwsId', 'SourceType', 'Status', 'CustSubscriptionId', 'SnsTopicArn' + @event_subscription[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/modify_db_instance.rb b/lib/fog/aws/parsers/rds/modify_db_instance.rb new file mode 100644 index 000000000..e1232cb2e --- /dev/null +++ b/lib/fog/aws/parsers/rds/modify_db_instance.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class ModifyDBInstance < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'ModifyDBInstanceResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['ModifyDBInstanceResult']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/modify_db_parameter_group.rb b/lib/fog/aws/parsers/rds/modify_db_parameter_group.rb new file mode 100644 index 000000000..60c63f49f --- /dev/null +++ b/lib/fog/aws/parsers/rds/modify_db_parameter_group.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module RDS + class ModifyDbParameterGroup < Fog::Parsers::Base + def reset + @response = { 'ModifyDBParameterGroupResult' => {}, 'ResponseMetadata' => {} } + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBParameterGroupName' + @response['ModifyDBParameterGroupResult']['DBParameterGroupName'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/promote_read_replica.rb b/lib/fog/aws/parsers/rds/promote_read_replica.rb new file mode 100644 index 000000000..80fbc0eca --- /dev/null +++ b/lib/fog/aws/parsers/rds/promote_read_replica.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class PromoteReadReplica < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'PromoteReadReplicaResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['PromoteReadReplicaResult']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/reboot_db_instance.rb b/lib/fog/aws/parsers/rds/reboot_db_instance.rb new file mode 100644 index 000000000..334d3db04 --- /dev/null +++ b/lib/fog/aws/parsers/rds/reboot_db_instance.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class RebootDBInstance < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'RebootDBInstanceResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + + when 'DBInstance' + @response['RebootDBInstanceResult']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/restore_db_instance_from_db_snapshot.rb b/lib/fog/aws/parsers/rds/restore_db_instance_from_db_snapshot.rb new file mode 100644 index 000000000..db12ec8fe --- /dev/null +++ b/lib/fog/aws/parsers/rds/restore_db_instance_from_db_snapshot.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class RestoreDBInstanceFromDBSnapshot < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'RestoreDBInstanceFromDBSnapshot' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['RestoreDBInstanceFromDBSnapshot']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/restore_db_instance_to_point_in_time.rb b/lib/fog/aws/parsers/rds/restore_db_instance_to_point_in_time.rb new file mode 100644 index 000000000..d9b3da02d --- /dev/null +++ b/lib/fog/aws/parsers/rds/restore_db_instance_to_point_in_time.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/db_parser' + + class RestoreDBInstanceToPointInTime < Fog::Parsers::AWS::RDS::DbParser + def reset + @response = { 'RestoreDBInstanceToPointInTime' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBInstance' + @response['RestoreDBInstanceToPointInTime']['DBInstance'] = @db_instance + @db_instance = fresh_instance + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/revoke_db_security_group_ingress.rb b/lib/fog/aws/parsers/rds/revoke_db_security_group_ingress.rb new file mode 100644 index 000000000..84d6bd871 --- /dev/null +++ b/lib/fog/aws/parsers/rds/revoke_db_security_group_ingress.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module AWS + module RDS + require 'fog/aws/parsers/rds/security_group_parser' + + class RevokeDBSecurityGroupIngress < Fog::Parsers::AWS::RDS::SecurityGroupParser + def reset + @response = { 'RevokeDBSecurityGroupIngressResult' => {}, 'ResponseMetadata' => {} } + super + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'DBSecurityGroup' then + @response['RevokeDBSecurityGroupIngressResult']['DBSecurityGroup'] = @security_group + @security_group = fresh_security_group + when 'RequestId' + @response['ResponseMetadata'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/security_group_parser.rb b/lib/fog/aws/parsers/rds/security_group_parser.rb new file mode 100644 index 000000000..e3e8be09d --- /dev/null +++ b/lib/fog/aws/parsers/rds/security_group_parser.rb @@ -0,0 +1,36 @@ +module Fog + module Parsers + module AWS + module RDS + class SecurityGroupParser < Fog::Parsers::Base + def reset + @security_group = fresh_security_group + end + + def fresh_security_group + {'EC2SecurityGroups' => [], 'IPRanges' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'EC2SecurityGroup', 'IPRange'; then @ingress = {} + end + end + + def end_element(name) + case name + when 'DBSecurityGroupDescription' then @security_group['DBSecurityGroupDescription'] = value + when 'DBSecurityGroupName' then @security_group['DBSecurityGroupName'] = value + when 'OwnerId' then @security_group['OwnerId'] = value + when 'EC2SecurityGroup', 'IPRange' + @security_group["#{name}s"] << @ingress unless @ingress.empty? + when 'EC2SecurityGroupName', 'EC2SecurityGroupOwnerId', 'CIDRIP', 'Status' + @ingress[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/snapshot_parser.rb b/lib/fog/aws/parsers/rds/snapshot_parser.rb new file mode 100644 index 000000000..f41534e14 --- /dev/null +++ b/lib/fog/aws/parsers/rds/snapshot_parser.rb @@ -0,0 +1,39 @@ +module Fog + module Parsers + module AWS + module RDS + class SnapshotParser < Fog::Parsers::Base + def reset + @db_snapshot = fresh_snapshot + end + + def fresh_snapshot + {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'AllocatedStorage' then @db_snapshot['AllocatedStorage'] = value.to_i + when 'AvailabilityZone' then @db_snapshot['AvailabilityZone'] = value + when 'DBInstanceIdentifier' then @db_snapshot['DBInstanceIdentifier'] = value + when 'DBSnapshotIdentifier' then @db_snapshot['DBSnapshotIdentifier'] = value + when 'Engine' then @db_snapshot['Engine'] = value + when 'EngineVersion' then @db_snapshot['EngineVersion'] = value + when 'InstanceCreateTime' then @db_snapshot['InstanceCreateTime'] = Time.parse value + when 'Iops' then @db_snapshot['Iops'] = value + when 'MasterUsername' then @db_snapshot['MasterUsername'] = value + when 'Port' then @db_snapshot['Port'] = value.to_i + when 'SnapshotCreateTime' then @db_snapshot['SnapshotCreateTime'] = Time.parse value + when 'SnapshotType' then @db_snapshot['SnapshotType'] = value + when 'Status' then @db_snapshot['Status'] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/subnet_group_parser.rb b/lib/fog/aws/parsers/rds/subnet_group_parser.rb new file mode 100644 index 000000000..03aea7b6a --- /dev/null +++ b/lib/fog/aws/parsers/rds/subnet_group_parser.rb @@ -0,0 +1,35 @@ +module Fog + module Parsers + module AWS + module RDS + class SubnetGroupParser < Fog::Parsers::Base + def reset + @db_subnet_group = fresh_subnet_group + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'VpcId' then @db_subnet_group['VpcId'] = value + when 'SubnetGroupStatus' then @db_subnet_group['SubnetGroupStatus'] = value + when 'DBSubnetGroupDescription' then @db_subnet_group['DBSubnetGroupDescription'] = value + when 'DBSubnetGroupName' then @db_subnet_group['DBSubnetGroupName'] = value + when 'SubnetIdentifier' then @db_subnet_group['Subnets'] << value + when 'Marker' + @response['DescribeDBSubnetGroupsResult']['Marker'] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + + def fresh_subnet_group + {'Subnets' => []} + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/tag_list_parser.rb b/lib/fog/aws/parsers/rds/tag_list_parser.rb new file mode 100644 index 000000000..76766c258 --- /dev/null +++ b/lib/fog/aws/parsers/rds/tag_list_parser.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module AWS + module RDS + # parses an XML-formatted list of resource tags from Aws + class TagListParser < Fog::Parsers::Base + # each tag is modeled as a String pair (2-element Array) + def reset + @this_key = nil + @this_value = nil + @tags = Hash.new + @response = {'ListTagsForResourceResult' => {'TagList' => {}}} + end + + def end_element(name) + super + case name + when 'Tag' + @tags[@this_key] = @this_value + @this_key, @this_value = nil, nil + when 'Key' + @this_key = value + when 'Value' + @this_value = value + when 'TagList' + @response['ListTagsForResourceResult']['TagList'] = @tags + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/cluster.rb b/lib/fog/aws/parsers/redshift/cluster.rb new file mode 100644 index 000000000..5fdb57aac --- /dev/null +++ b/lib/fog/aws/parsers/redshift/cluster.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_parser' + + class Cluster < ClusterParser + def reset + super + @response = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'Cluster' + @response = {name => @cluster} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/cluster_parser.rb b/lib/fog/aws/parsers/redshift/cluster_parser.rb new file mode 100644 index 000000000..b0a4bb9c4 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/cluster_parser.rb @@ -0,0 +1,143 @@ +module Fog + module Parsers + module Redshift + module AWS + class ClusterParser < Fog::Parsers::Base + # :cluster_identifier - (String) + # :node_type - (String) + # :cluster_status - (String) + # :modify_status - (String) + # :master_username - (String) + # :db_name - (String) + # :endpoint - (Hash) + # :address - (String) + # :port - (Integer) + # :cluster_create_time - (Time) + # :automated_snapshot_retention_period - (Integer) + # :cluster_security_groups - (Array) + # :cluster_security_group_name - (String) + # :status - (String) + # :vpc_security_groups - (Array) + # :vpc_security_group_id - (String) + # :status - (String) + # :cluster_parameter_groups - (Array) + # :parameter_group_name - (String) + # :parameter_apply_status - (String) + # :cluster_subnet_group_name - (String) + # :vpc_id - (String) + # :availability_zone - (String) + # :preferred_maintenance_window - (String) + # :pending_modified_values - (Hash) + # :master_user_password - (String) + # :node_type - (String) + # :number_of_nodes - (Integer) + # :cluster_type - (String) + # :cluster_version - (String) + # :automated_snapshot_retention_period - (Integer) + # :cluster_version - (String) + # :allow_version_upgrade - (Boolean) + # :number_of_nodes - (Integer) + # :publicly_accessible - (Boolean) + # :encrypted - (Boolean) + # :restore_status - (Hash) + # :status - (String) + # :current_restore_rate_in_mega_bytes_per_second - (Numeric) + # :snapshot_size_in_mega_bytes - (Integer) + # :progress_in_mega_bytes - (Integer) + # :elapsed_time_in_seconds - (Integer) + # :estimated_time_to_completion_in_seconds - (Integer) + + def reset + @cluster = fresh_cluster + end + + def fresh_cluster + { 'ClusterParameterGroups' => [], 'ClusterSecurityGroups' => [], 'VpcSecurityGroups' => [], + 'EndPoint' => {}, 'PendingModifiedValues'=> {}, 'RestoreStatus' => {}} + end + + def start_element(name, attrs = []) + super + case name + when 'ClusterSecurityGroups' + @in_cluster_security_groups = true + @cluster_security_group = {} + when 'ClusterParameterGroups' + @cluster_parameter_group = {} + when 'VpcSecurityGroups' + @in_vpc_security_groups = true + @vpc_security_group = {} + when 'PendingModifiedValues' + @in_pending_modified_values = true + end + end + + def end_element(name) + case name + when 'AvailabilityZone', 'ClusterIdentifier', 'ClusterStatus', 'ClusterSubnetGroupName', 'DBName', + 'MasterUsername', 'ModifyStatus', 'PreferredMaintenanceWindow', 'VpcId' + @cluster[name] = value + when 'ClusterCreateTime' + @cluster[name] = Time.parse(value) + when 'AllowVersionUpgrade', 'Encrypted', 'PubliclyAccessible' + @cluster[name] = (value == "true") + when 'Address' + @cluster['EndPoint'][name] = value + when 'Port' + @cluster['EndPoint'][name] = value.to_i + when 'NodeType', 'ClusterVersion' + if @in_pending_modified_values + @cluster['PendingModifiedValues'][name] = value + else + @cluster[name] = value + end + when 'NumberOfNodes', 'AutomatedSnapshotRetentionPeriod' + if @in_pending_modified_values + @cluster['PendingModifiedValues'][name] = value.to_i + else + @cluster[name] = value.to_i + end + when 'MasterUserPassword', 'ClusterType' + @cluster['PendingModifiedValues'][name] = value + when 'Status' + if @in_vpc_security_groups + @vpc_security_group[name] = value + elsif @in_cluster_security_groups + @cluster_security_group[name] = value + else + @cluster['RestoreStatus'][name] = value + end + when 'ParameterGroupName', 'ParameterApplyStatus' + @cluster_parameter_group[name] = value + when 'ClusterSecurityGroupName' + @cluster_security_group[name] = value + when 'VpcSecurityGroupId' + @vpc_security_group[name] = value + when 'SnapshotSizeInMegaBytes', 'ProgressInMegaBytes', 'ElapsedTimeInSeconds', 'EstimatedTimeToCompletionInSeconds' + @cluster['RestoreStatus'][name] = value.to_i + when 'CurrentRestoreRateInMegaBytesPerSecond' + @cluster['RestoreStatus'][name] = value.to_f + + when 'ClusterSecurityGroups' + @in_cluster_security_groups = false + when 'VpcSecurityGroups' + @in_vpc_security_groups = false + when 'PendingModifiedValues' + @in_pending_modified_values = false + + when 'ClusterParameterGroup' + @cluster['ClusterParameterGroups'] << {name => @cluster_parameter_group} + @cluster_parameter_group = {} + when 'ClusterSecurityGroup' + @cluster['ClusterSecurityGroups'] << {name => @cluster_security_group} + @cluster_security_group = {} + when 'VpcSecurityGroup' + @cluster['VpcSecurityGroups'] << {name => @vpc_security_group} + @vpc_security_group = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/cluster_security_group_parser.rb b/lib/fog/aws/parsers/redshift/cluster_security_group_parser.rb new file mode 100644 index 000000000..9c1d639b9 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/cluster_security_group_parser.rb @@ -0,0 +1,49 @@ +module Fog + module Parsers + module Redshift + module AWS + class ClusterSecurityGroupParser < Fog::Parsers::Base + # :cluster_security_group_name - (String) + # :description - (String) + # :ec_2_security_groups - (Array) + # :status - (String) + # :ec2_security_group_name - (String) + # :ec2_security_group_owner_id - (String) + # :ip_ranges - (Array) + # :status - (String) + # :cidrip - (String) + + def reset + @cluster_security_group = fresh_cluster_security_group + end + + def fresh_cluster_security_group + {'EC2SecurityGroups' => [], 'IPRanges' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'EC2SecurityGroups', 'IPRanges' + @list = {} + @list_name = name + end + end + + def end_element(name) + super + case name + when 'ClusterSecurityGroupName', 'Description' + @cluster_security_group[name] = value + when 'EC2SecurityGroupName', 'EC2SecurityGroupOwnerId', 'CIDRIP', 'Status' + @list[name] = value + when 'EC2SecurityGroup', 'IPRange' + @cluster_security_group[@list_name] << {name => @list} + @list = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/cluster_snapshot.rb b/lib/fog/aws/parsers/redshift/cluster_snapshot.rb new file mode 100644 index 000000000..c74e514cd --- /dev/null +++ b/lib/fog/aws/parsers/redshift/cluster_snapshot.rb @@ -0,0 +1,31 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_snapshot_parser' + + class ClusterSnapshot < ClusterSnapshotParser + # :parameter_group_name - (String) + # :parameter_group_status - (String) + + def reset + super + @response = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'Snapshot' + @response = @snapshot + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/cluster_snapshot_parser.rb b/lib/fog/aws/parsers/redshift/cluster_snapshot_parser.rb new file mode 100644 index 000000000..2aa62c76d --- /dev/null +++ b/lib/fog/aws/parsers/redshift/cluster_snapshot_parser.rb @@ -0,0 +1,65 @@ +module Fog + module Parsers + module Redshift + module AWS + class ClusterSnapshotParser < Fog::Parsers::Base + # :snapshot_identifier - (String) + # :cluster_identifier - (String) + # :snapshot_create_time - (Time) + # :status - (String) + # :port - (Integer) + # :availability_zone - (String) + # :cluster_create_time - (Time) + # :master_username - (String) + # :cluster_version - (String) + # :snapshot_type - (String) + # :node_type - (String) + # :number_of_nodes - (Integer) + # :db_name - (String) + # :vpc_id - (String) + # :encrypted - (Boolean) + # :accounts_with_restore_access - (Array) + # :account_id - (String) + # :owner_account - (String) + # :total_backup_size_in_mega_bytes - (Numeric) + # :actual_incremental_backup_size_in_mega_bytes - (Numeric) + # :backup_progress_in_mega_bytes - (Numeric) + # :current_backup_rate_in_mega_bytes_per_second - (Numeric) + # :estimated_seconds_to_completion - (Integer) + # :elapsed_time_in_seconds - (Integer) + + def reset + @snapshot = fresh_snapshot + end + + def fresh_snapshot + {'Snapshot' => { 'AccountsWithRestoreAccess' => [] }} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'SnapshotIdentifier', 'ClusterIdentifier', 'Status', 'AvailabilityZone', 'MasterUsername', 'ClusterVersion', 'SnapshotType', 'NodeType', + 'DBName', 'VpcId', 'OwnerAccount' + @snapshot['Snapshot'][name] = value + when 'Port', 'NumberOfNodes', 'ElapsedTimeInSeconds', 'EstimatedSecondsToCompletion' + @snapshot['Snapshot'][name] = value.to_i + when 'SnapshotCreateTime', 'ClusterCreateTime' + @snapshot['Snapshot'][name] = Time.parse(value) + when 'Encrypted' + @snapshot['Snapshot'][name] = (value == "true") + when 'TotalBackupSizeInMegaBytes', 'ActualIncrementalBackupSizeInMegaBytes', 'BackupProgressInMegaBytes', 'CurrentBackupRateInMegaBytesPerSecond' + @snapshot['Snapshot'][name] = value.to_f + when 'AccountId' + @snapshot['Snapshot']['AccountsWithRestoreAccess'] << value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/cluster_subnet_group_parser.rb b/lib/fog/aws/parsers/redshift/cluster_subnet_group_parser.rb new file mode 100644 index 000000000..7374013e1 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/cluster_subnet_group_parser.rb @@ -0,0 +1,50 @@ +module Fog + module Parsers + module Redshift + module AWS + class ClusterSubnetGroupParser < Fog::Parsers::Base + # :cluster_subnet_group_name - (String) + # :description - (String) + # :vpc_id - (String) + # :subnet_group_status - (String) + # :subnets - (Array) + # :subnet_identifier - (String) + # :subnet_availability_zone - (Hash) + # :name - (String) + # :subnet_status - (String) + + def reset + @response = { 'Subnets' => [] } + end + + def fresh_subnet + {'SubnetAvailabilityZone'=>{}} + end + + def start_element(name, attrs = []) + super + case name + when 'Subnets' + @subnet = fresh_subnet + end + end + + def end_element(name) + super + case name + when 'ClusterSubnetGroupName', 'Desciption', 'VpcId', 'SubnetGroupStatus' + @response[name] = value + when 'SubnetIdentifier', 'SubnetStatus' + @subnet[name] = value + when 'Name' + @subnet['SubnetAvailabilityZone'][name] = value + when 'Subnet' + @response['Subnets'] << {name => @subnet} + @subnet = fresh_subnet + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/create_cluster_parameter_group.rb b/lib/fog/aws/parsers/redshift/create_cluster_parameter_group.rb new file mode 100644 index 000000000..50b85dc49 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/create_cluster_parameter_group.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module Redshift + module AWS + class CreateClusterParameterGroup < Fog::Parsers::Base + # :parameter_group_name - (String) + # :parameter_group_family - (String) + # :description - (String) + + def reset + @response = {'ClusterParameterGroup'=>{}} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'ParameterGroupName', 'ParameterGroupFamily', 'Description' + @response['ClusterParameterGroup'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/create_cluster_security_group.rb b/lib/fog/aws/parsers/redshift/create_cluster_security_group.rb new file mode 100644 index 000000000..2e542ac28 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/create_cluster_security_group.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_security_group_parser' + + class CreateClusterSecurityGroup < ClusterSecurityGroupParser + # :cluster_security_group + + def reset + super + @response = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'ClusterSecurityGroup' + @response['ClusterSecurityGroup'] = @cluster_security_group + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_cluster_parameter_groups.rb b/lib/fog/aws/parsers/redshift/describe_cluster_parameter_groups.rb new file mode 100644 index 000000000..3b680e125 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_cluster_parameter_groups.rb @@ -0,0 +1,40 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeClusterParameterGroups < Fog::Parsers::Base + # :marker - (String) + # :parameter_groups - (Array) + # :parameter_group_name - (String) + # :parameter_group_family - (String) + # :description - (String) + + def reset + @response = { 'ParameterGroups' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'ParameterGroups' + @parameter_group = {} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'ParameterGroupName', 'ParameterGroupFamily', 'Description' + @parameter_group[name] = value + when 'ClusterParameterGroup' + @response['ParameterGroups'] << {name => @parameter_group} + @parameter_group = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_cluster_parameters.rb b/lib/fog/aws/parsers/redshift/describe_cluster_parameters.rb new file mode 100644 index 000000000..ef6507d5a --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_cluster_parameters.rb @@ -0,0 +1,47 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeClusterParameters < Fog::Parsers::Base + # :marker - (String) + # :parameters - (Array) + # :parameter_name - (String) + # :parameter_value - (String) + # :description - (String) + # :source - (String) + # :data_type - (String) + # :allowed_values - (String) + # :is_modifiable - (Boolean) + # :minimum_engine_version - (String) + + def reset + @response = { 'Parameters' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Parameters' + @parameter = {} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'ParameterName', 'ParameterValue', 'Description', 'Source', 'DataType', 'AllowedValues', 'MinimumEngineVersion' + @parameter[name] = value + when 'IsModifiable' + @parameter[name] = (value == "true") + when 'Parameter' + @response['Parameters'] << {name => @parameter} + @parameter = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_cluster_security_groups.rb b/lib/fog/aws/parsers/redshift/describe_cluster_security_groups.rb new file mode 100644 index 000000000..50d492b7d --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_cluster_security_groups.rb @@ -0,0 +1,37 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_security_group_parser' + + class DescribeClusterSecurityGroups < ClusterSecurityGroupParser + # :marker - (String) + # :cluster_security_groups - (Array) + + def reset + @response = { 'ClusterSecurityGroups' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'ClusterSecurityGroups' + @cluster_security_group = fresh_cluster_security_group + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'ClusterSecurityGroup' + @response['ClusterSecurityGroups'] << { name => @cluster_security_group } + @cluster_security_group = fresh_cluster_security_group + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_cluster_snapshots.rb b/lib/fog/aws/parsers/redshift/describe_cluster_snapshots.rb new file mode 100644 index 000000000..20f22d680 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_cluster_snapshots.rb @@ -0,0 +1,37 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_snapshot_parser' + + class DescribeClusterSnapshots < ClusterSnapshotParser + # :marker - (String) + # :snapshots - (Array) + + def reset + @response = { 'Snapshots' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Snapshots' + @snapshot = fresh_snapshot + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'Snapshot' + @response['Snapshots'] << @snapshot + @snapshot = fresh_snapshot + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_cluster_subnet_groups.rb b/lib/fog/aws/parsers/redshift/describe_cluster_subnet_groups.rb new file mode 100644 index 000000000..53981a87a --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_cluster_subnet_groups.rb @@ -0,0 +1,55 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeClusterSubnetGroups < Fog::Parsers::Base + # :marker - (String) + # :cluster_subnet_groups - (Array) + # :cluster_subnet_group_name - (String) + # :description - (String) + # :vpc_id - (String) + # :subnet_group_status - (String) + # :subnets - (Array) + # :subnet_identifier - (String) + # :subnet_availability_zone - (Hash) + # :name - (String) + # :subnet_status - (String) + + def reset + @response = { 'ClusterSubnetGroups' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'ClusterSubnetGroups' + @cluster_subnet_group = {'Subnets' => []} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'ClusterSubnetGroup' + @response['ClusterSubnetGroups'] << {name => @cluster_subnet_group} + @cluster_subnet_group = {'Subnets' => []} + when 'ClusterSubnetGroupName', 'Description', 'VpcId', 'SubnetGroupStatus' + @cluster_subnet_group[name] = value + when 'Subnet' + @cluster_subnet_group['Subnets'] << {name => @subnet} if @subnet + @subnet = {} + when 'SubnetAvailabilityZone' + @subnet['SubnetAvailabilityZone'] = {} + when 'Name' + @subnet['SubnetAvailabilityZone']['Name'] = value + when 'SubnetIdentifier', 'SubnetStatus' + @subnet[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_cluster_versions.rb b/lib/fog/aws/parsers/redshift/describe_cluster_versions.rb new file mode 100644 index 000000000..d6a2f39e0 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_cluster_versions.rb @@ -0,0 +1,50 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeClusterVersions < Fog::Parsers::Base + # :marker - (String) + # :cluster_versions - (Array) + # :cluster_version - (String) + # :cluster_parameter_group_family - (String) + # :description - (String) + + def reset + @response = { 'ClusterVersions' => [] } + @cluster_version_depth = 0 + end + + def start_element(name, attrs = []) + super + case name + when 'ClusterVersions' + @cluster_version = {} + when 'ClusterVersion' + # Sadly, there are two nodes of different type named cluster_version + # that are nested, so we keep track of which one we're in + @cluster_version_depth += 1 + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'ClusterVersion' + @cluster_version_depth -= 1 + if @cluster_version_depth == 0 + @response['ClusterVersions'] << {name => @cluster_version} + @cluster_version = {} + else + @cluster_version[name] = value + end + when 'ClusterParameterGroupFamily', 'Description' + @cluster_version[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_clusters.rb b/lib/fog/aws/parsers/redshift/describe_clusters.rb new file mode 100644 index 000000000..230767384 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_clusters.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_parser' + + class DescribeClusters < ClusterParser + def reset + super + @response = {"ClusterSet" => []} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'Cluster' + @response["ClusterSet"] << {name => @cluster} + @cluster = fresh_cluster + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_default_cluster_parameters.rb b/lib/fog/aws/parsers/redshift/describe_default_cluster_parameters.rb new file mode 100644 index 000000000..8a7bca710 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_default_cluster_parameters.rb @@ -0,0 +1,48 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeDefaultClusterParameters < Fog::Parsers::Base + # :marker - (String) + # :parameter_group_family - (String) + # :parameters - (Array) + # :parameter_name - (String) + # :parameter_value - (String) + # :description - (String) + # :source - (String) + # :data_type - (String) + # :allowed_values - (String) + # :is_modifiable - (Boolean) + # :minimum_engine_version - (String) + + def reset + @response = { 'Parameters' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Parameters' + @parameter = {} + end + end + + def end_element(name) + super + case name + when 'Marker', 'ParameterGroupFamily' + @response[name] = value + when 'ParameterName', 'ParameterValue', 'Description', 'Source', 'DataType', 'AllowedValues', 'MinimumEngineVersion' + @parameter[name] = value + when 'IsModifiable' + @parameter[name] = (value == "true") + when 'Parameter' + @response['Parameters'] << {name => @parameter} + @parameter = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_events.rb b/lib/fog/aws/parsers/redshift/describe_events.rb new file mode 100644 index 000000000..e224f9a0f --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_events.rb @@ -0,0 +1,43 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeEvents < Fog::Parsers::Base + # :marker - (String) + # :events - (Array) + # :source_identifier - (String) + # :source_type - (String) + # :message - (String) + # :date - (Time) + + def reset + @response = { 'Events' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Events' + @event = {} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'SourceIdentifier', 'SourceType', 'Message' + @event[name] = value + when 'Date' + @event[name] = Time.parse(value) + when 'Event' + @response['Events'] << {name => @event} + @event = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_orderable_cluster_options.rb b/lib/fog/aws/parsers/redshift/describe_orderable_cluster_options.rb new file mode 100644 index 000000000..b99a1d7ac --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_orderable_cluster_options.rb @@ -0,0 +1,53 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeOrderableClusterOptions < Fog::Parsers::Base + # :marker - (String) + # :orderable_cluster_options - (Array) + # :cluster_version - (String) + # :cluster_type - (String) + # :node_type - (String) + # :availability_zones - (Array) + # :name - (String) + + def reset + @response = { 'OrderableClusterOptions' => [] } + end + + def fresh_orderable_cluster_option + {'AvailabilityZones' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'OrderableClusterOptions' + @orderable_cluster_option = fresh_orderable_cluster_option + when 'AvailabilityZones' + @availability_zone = {} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'ClusterVersion', 'ClusterType', 'NodeType' + @orderable_cluster_option[name] = value + when 'Name' + @availability_zone[name] = value + when 'AvailabilityZone' + @orderable_cluster_option['AvailabilityZones'] << {name => @availability_zone} + @availability_zone = {} + when 'OrderableClusterOption' + @response['OrderableClusterOptions'] << {name => @orderable_cluster_option} + @orderable_cluster_option = fresh_orderable_cluster_option + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_reserved_node_offerings.rb b/lib/fog/aws/parsers/redshift/describe_reserved_node_offerings.rb new file mode 100644 index 000000000..b43effed7 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_reserved_node_offerings.rb @@ -0,0 +1,63 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeReservedNodeOfferings < Fog::Parsers::Base + # :marker - (String) + # :reserved_node_offerings - (Array) + # :reserved_node_offering_id - (String) + # :node_type - (String) + # :duration - (Integer) + # :fixed_price - (Numeric) + # :usage_price - (Numeric) + # :currency_code - (String) + # :offering_type - (String) + # :recurring_charges - (Array) + # :recurring_charge_amount - (Numeric) + # :recurring_charge_frequency - (String) + def reset + @response = { 'ReservedNodeOfferings' => [] } + end + + def fresh_reserved_node_offering + {'RecurringCharges' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'ReservedNodeOfferings' + @reserved_node_offering = fresh_reserved_node_offering + when 'RecurringCharges' + @recurring_charge = {} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'Duration' + @reserved_node_offering[name] = value.to_i + when 'FixedPrice', 'UsagePrice' + @reserved_node_offering[name] = value.to_f + when 'CurrencyCode', 'OfferingType', 'NodeType', 'ReservedNodeOfferingId' + @reserved_node_offering[name] = value + when 'RecurringChargeAmount' + @recurring_charge[name] = value.to_f + when 'RecurringChargeFrequency' + @recurring_charge[name] = value + when 'RecurringCharge' + @reserved_node_offering['RecurringCharges'] << {name => @recurring_charge} + @recurring_charge = {} + when 'ReservedNodeOffering' + @response['ReservedNodeOfferings'] << {name => @reserved_node_offering} + @reserved_node_offering = fresh_reserved_node_offering + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_reserved_nodes.rb b/lib/fog/aws/parsers/redshift/describe_reserved_nodes.rb new file mode 100644 index 000000000..23a398950 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_reserved_nodes.rb @@ -0,0 +1,70 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeReservedNodes < Fog::Parsers::Base + # :marker - (String) + # :reserved_nodes - (Array) + # :reserved_node_id - (String) + # :reserved_node_offering_id - (String) + # :node_type - (String) + # :start_time - (Time) + # :duration - (Integer) + # :fixed_price - (Numeric) + # :usage_price - (Numeric) + # :currency_code - (String) + # :node_count - (Integer) + # :state - (String) + # :offering_type - (String) + # :recurring_charges - (Array) + # :recurring_charge_amount - (Numeric) + # :recurring_charge_frequency - (String) + + def reset + @response = { 'ReservedNodes' => [] } + end + + def fresh_reserved_nodes + {'RecurringCharges' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'ReservedNodes' + @reserved_node = fresh_reserved_nodes + when 'RecurringCharges' + @recurring_charge = {} + end + end + + def end_element(name) + super + case name + when 'Marker' + @response[name] = value + when 'Duration', 'NodeCount' + @reserved_node[name] = value.to_i + when 'StartTime' + @reserved_node[name] = Time.parse(value) + when 'FixedPrice', 'UsagePrice' + @reserved_node[name] = value.to_f + when 'CurrencyCode', 'OfferingType', 'NodeType', 'ReservedNodeOfferingId', 'ReservedNodeId', 'State' + @reserved_node[name] = value + when 'RecurringChargeAmount' + @recurring_charge[name] = value.to_f + when 'RecurringChargeFrequency' + @recurring_charge[name] = value + when 'RecurringCharge' + @reserved_node['RecurringCharges'] << {name => @recurring_charge} + @recurring_charge = {} + when 'ReservedNode' + @response['ReservedNodes'] << {name => @reserved_node} + @reserved_node = fresh_reserved_nodes + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/describe_resize.rb b/lib/fog/aws/parsers/redshift/describe_resize.rb new file mode 100644 index 000000000..921113972 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/describe_resize.rb @@ -0,0 +1,58 @@ +module Fog + module Parsers + module Redshift + module AWS + class DescribeResize < Fog::Parsers::Base + # :target_node_type - (String) + # :target_number_of_nodes - (Integer) + # :target_cluster_type - (String) + # :status - (String) + # :import_tables_completed - (Array) + # :import_tables_in_progress - (Array) + # :import_tables_not_started - (Array) + def reset + @response = { 'ImportTablesCompleted' => [], 'ImportTablesInProgress' => [], 'ImportTablesNotStarted' => []} + end + + def start_element(name, attrs = []) + super + case name + when 'ImportTablesCompleted' + @in_import_tables_completed = true + when 'ImportTablesInProgress' + @in_import_tables_in_progress = true + when 'ImportTablesNotStarted' + @in_import_tables_not_started = true + end + end + + def end_element(name) + super + case name + when 'TargetNodeType', 'TargetClusterType', 'Status' + @response[name] = value + when 'TargetNumberOfNodes' + @response[name] = value.to_i + when 'ImportTablesCompleted' + @in_import_tables_completed = false + when 'ImportTablesInProgress' + @in_import_tables_in_progress = false + when 'ImportTablesNotStarted' + @in_import_tables_not_started = false + when 'member' + if @in_import_tables_completed + @response['ImportTablesCompleted'] << value + end + if @in_import_tables_not_started + @response['ImportTablesNotStarted'] << value + end + if @in_import_tables_in_progress + @response['ImportTablesInProgress'] << value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/purchase_reserved_node_offering.rb b/lib/fog/aws/parsers/redshift/purchase_reserved_node_offering.rb new file mode 100644 index 000000000..441d44d74 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/purchase_reserved_node_offering.rb @@ -0,0 +1,56 @@ +module Fog + module Parsers + module Redshift + module AWS + class PurchaseReservedNodeOffering < Fog::Parsers::Base + # :reserved_node_id - (String) + # :reserved_node_offering_id - (String) + # :node_type - (String) + # :start_time - (Time) + # :duration - (Integer) + # :fixed_price - (Numeric) + # :usage_price - (Numeric) + # :currency_code - (String) + # :node_count - (Integer) + # :state - (String) + # :offering_type - (String) + # :recurring_charges - (Array) + # :recurring_charge_amount - (Numeric) + # :recurring_charge_frequency - (String) + def reset + @response = { 'RecurringCharges' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'RecurringCharges' + @recurring_charge = {} + end + end + + def end_element(name) + super + case name + when 'ReservedNodeId', 'ReservedNodeOfferingId', 'NodeType', 'CurrencyCode', 'State', 'OfferingType' + @response[name] = value + when 'Duration', 'NodeCount' + @response[name] = value.to_i + when 'FixedPrice', 'UsagePrice' + @response[name] = value.to_f + when 'StartTime' + @response[name] = Time.parse(value) + when 'RecurringChargeAmount' + @recurring_charge[name] = value.to_f + when 'RecurringChargeFrequency' + @recurring_charge[name] = value + when 'RecurringCharge' + @response['RecurringCharges'] << {name => @recurring_charge} + @recurring_charge = {} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/revoke_cluster_security_group_ingress.rb b/lib/fog/aws/parsers/redshift/revoke_cluster_security_group_ingress.rb new file mode 100644 index 000000000..70f4452a8 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/revoke_cluster_security_group_ingress.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module Redshift + module AWS + require 'fog/aws/parsers/redshift/cluster_security_group_parser' + + class RevokeClusterSecurityGroupIngress < ClusterSecurityGroupParser + # :cluster_security_group + + def reset + super + @response = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'ClusterSecurityGroup' + @response['ClusterSecurityGroup'] = @cluster_security_group + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/redshift/update_cluster_parameter_group_parser.rb b/lib/fog/aws/parsers/redshift/update_cluster_parameter_group_parser.rb new file mode 100644 index 000000000..4d0a029d3 --- /dev/null +++ b/lib/fog/aws/parsers/redshift/update_cluster_parameter_group_parser.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module Redshift + module AWS + class UpdateClusterParameterGroupParser < Fog::Parsers::Base + # :parameter_group_name - (String) + # :parameter_group_status - (String) + + def reset + @response = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + super + case name + when 'ParameterGroupName', 'ParameterGroupStatus' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/delete_verified_email_address.rb b/lib/fog/aws/parsers/ses/delete_verified_email_address.rb new file mode 100644 index 000000000..9d357f064 --- /dev/null +++ b/lib/fog/aws/parsers/ses/delete_verified_email_address.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SES + class DeleteVerifiedEmailAddress < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/get_send_quota.rb b/lib/fog/aws/parsers/ses/get_send_quota.rb new file mode 100644 index 000000000..9430d4bb1 --- /dev/null +++ b/lib/fog/aws/parsers/ses/get_send_quota.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SES + class GetSendQuota < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when "Max24HourSend", "MaxSendRate", "SentLast24Hours" + @response[name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/get_send_statistics.rb b/lib/fog/aws/parsers/ses/get_send_statistics.rb new file mode 100644 index 000000000..263848ea3 --- /dev/null +++ b/lib/fog/aws/parsers/ses/get_send_statistics.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module SES + class GetSendStatistics < Fog::Parsers::Base + def reset + @response = { 'SendDataPoints' => [], 'ResponseMetadata' => {} } + @send_data_point = {} + end + + def end_element(name) + case name + when "Bounces", "Complaints", "DeliveryAttempts", "Rejects", "Timestamp" + @send_data_point[name] = value + when 'member' + @response['SendDataPoints'] << @send_data_point + @send_data_point = {} + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/list_verified_email_addresses.rb b/lib/fog/aws/parsers/ses/list_verified_email_addresses.rb new file mode 100644 index 000000000..32fdf7130 --- /dev/null +++ b/lib/fog/aws/parsers/ses/list_verified_email_addresses.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SES + class ListVerifiedEmailAddresses < Fog::Parsers::Base + def reset + @response = { 'VerifiedEmailAddresses' => [], 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'member' + @response['VerifiedEmailAddresses'] << value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/send_email.rb b/lib/fog/aws/parsers/ses/send_email.rb new file mode 100644 index 000000000..c98378e2b --- /dev/null +++ b/lib/fog/aws/parsers/ses/send_email.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SES + class SendEmail < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'MessageId' + @response[name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/send_raw_email.rb b/lib/fog/aws/parsers/ses/send_raw_email.rb new file mode 100644 index 000000000..1229dbd4f --- /dev/null +++ b/lib/fog/aws/parsers/ses/send_raw_email.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SES + class SendRawEmail < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'MessageId' + @response[name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/verify_domain_identity.rb b/lib/fog/aws/parsers/ses/verify_domain_identity.rb new file mode 100644 index 000000000..63a5b99c7 --- /dev/null +++ b/lib/fog/aws/parsers/ses/verify_domain_identity.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SES + class VerifyDomainIdentity < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'VerificationToken' + @response[name] = value + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/ses/verify_email_address.rb b/lib/fog/aws/parsers/ses/verify_email_address.rb new file mode 100644 index 000000000..f557f040d --- /dev/null +++ b/lib/fog/aws/parsers/ses/verify_email_address.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SES + class VerifyEmailAddress < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/simpledb/basic.rb b/lib/fog/aws/parsers/simpledb/basic.rb new file mode 100644 index 000000000..7550ce800 --- /dev/null +++ b/lib/fog/aws/parsers/simpledb/basic.rb @@ -0,0 +1,27 @@ +module Fog + module Parsers + module AWS + module SimpleDB + class Basic < Fog::Parsers::Base + def initialize(nil_string) + @nil_string = nil_string + reset + end + + def end_element(name) + case(name) + when 'BoxUsage' + response[name] = value.to_f + when 'RequestId' + response[name] = value + end + end + + def sdb_decode(value) + value.eql?(@nil_string) ? nil : value + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/simpledb/domain_metadata.rb b/lib/fog/aws/parsers/simpledb/domain_metadata.rb new file mode 100644 index 000000000..df5acc378 --- /dev/null +++ b/lib/fog/aws/parsers/simpledb/domain_metadata.rb @@ -0,0 +1,28 @@ +require 'fog/aws/parsers/simpledb/basic' + +module Fog + module Parsers + module AWS + module SimpleDB + class DomainMetadata < Fog::Parsers::AWS::SimpleDB::Basic + def reset + @response = {} + end + + def end_element(name) + case name + when 'AttributeNameCount', 'AttributeNamesSizeBytes', 'AttributeValueCount', 'AttributeValuesSizeBytes', 'ItemCount', 'ItemNamesSizeBytes' + response[name] = value.to_i + when 'BoxUsage' + response[name] = value.to_f + when 'RequestId' + response[name] = value + when 'Timestamp' + response[name] = Time.at(value.to_i) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/simpledb/get_attributes.rb b/lib/fog/aws/parsers/simpledb/get_attributes.rb new file mode 100644 index 000000000..7757d1bd1 --- /dev/null +++ b/lib/fog/aws/parsers/simpledb/get_attributes.rb @@ -0,0 +1,32 @@ +require 'fog/aws/parsers/simpledb/basic' + +module Fog + module Parsers + module AWS + module SimpleDB + class GetAttributes < Fog::Parsers::AWS::SimpleDB::Basic + def reset + @attribute = nil + @response = { 'Attributes' => {} } + end + + def end_element(name) + case name + when 'Attribute' + @attribute = nil + when 'BoxUsage' + response[name] = value.to_f + when 'Name' + @attribute = value + response['Attributes'][@attribute] ||= [] + when 'RequestId' + response[name] = value + when 'Value' + response['Attributes'][@attribute] << sdb_decode(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/simpledb/list_domains.rb b/lib/fog/aws/parsers/simpledb/list_domains.rb new file mode 100644 index 000000000..998f4baf8 --- /dev/null +++ b/lib/fog/aws/parsers/simpledb/list_domains.rb @@ -0,0 +1,26 @@ +require 'fog/aws/parsers/simpledb/basic' + +module Fog + module Parsers + module AWS + module SimpleDB + class ListDomains < Fog::Parsers::AWS::SimpleDB::Basic + def reset + @response = { 'Domains' => [] } + end + + def end_element(name) + case(name) + when 'BoxUsage' + response[name] = value.to_f + when 'DomainName' + response['Domains'] << value + when 'NextToken', 'RequestId' + response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/simpledb/select.rb b/lib/fog/aws/parsers/simpledb/select.rb new file mode 100644 index 000000000..cb616afb6 --- /dev/null +++ b/lib/fog/aws/parsers/simpledb/select.rb @@ -0,0 +1,37 @@ +require 'fog/aws/parsers/simpledb/basic' + +module Fog + module Parsers + module AWS + module SimpleDB + class Select < Fog::Parsers::AWS::SimpleDB::Basic + def reset + @item_name = @attribute_name = nil + @response = { 'Items' => {} } + end + + def end_element(name) + case name + when 'BoxUsage' + response[name] = value.to_f + when 'Item' + @item_name = @attribute_name = nil + when 'Name' + if @item_name.nil? + @item_name = value + response['Items'][@item_name] = {} + else + @attribute_name = value + response['Items'][@item_name][@attribute_name] ||= [] + end + when 'NextToken', 'RequestId' + response[name] = value + when 'Value' + response['Items'][@item_name][@attribute_name] << sdb_decode(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/add_permission.rb b/lib/fog/aws/parsers/sns/add_permission.rb new file mode 100644 index 000000000..04cdd6e8b --- /dev/null +++ b/lib/fog/aws/parsers/sns/add_permission.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class AddPermission < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/confirm_subscription.rb b/lib/fog/aws/parsers/sns/confirm_subscription.rb new file mode 100644 index 000000000..bd6922378 --- /dev/null +++ b/lib/fog/aws/parsers/sns/confirm_subscription.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class ConfirmSubscription < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'SubscriptionArn', 'RequestId' + @response[name] = @value.strip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/create_topic.rb b/lib/fog/aws/parsers/sns/create_topic.rb new file mode 100644 index 000000000..311d8ae15 --- /dev/null +++ b/lib/fog/aws/parsers/sns/create_topic.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class CreateTopic < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'TopicArn', 'RequestId' + @response[name] = @value.strip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/delete_topic.rb b/lib/fog/aws/parsers/sns/delete_topic.rb new file mode 100644 index 000000000..7739a0e33 --- /dev/null +++ b/lib/fog/aws/parsers/sns/delete_topic.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class DeleteTopic < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/get_topic_attributes.rb b/lib/fog/aws/parsers/sns/get_topic_attributes.rb new file mode 100644 index 000000000..c5d851ce9 --- /dev/null +++ b/lib/fog/aws/parsers/sns/get_topic_attributes.rb @@ -0,0 +1,29 @@ +module Fog + module Parsers + module AWS + module SNS + class GetTopicAttributes < Fog::Parsers::Base + def reset + @response = { 'Attributes' => {} } + end + + def end_element(name) + case name + when 'key' + @key = @value.rstrip + when 'value' + case @key + when 'SubscriptionsConfirmed', 'SubscriptionsDeleted', 'SubscriptionsPending' + @response['Attributes'][@key] = @value.rstrip.to_i + else + @response['Attributes'][@key] = (@value && @value.rstrip) || nil + end + when 'RequestId' + @response[name] = @value.rstrip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/list_subscriptions.rb b/lib/fog/aws/parsers/sns/list_subscriptions.rb new file mode 100644 index 000000000..02533d934 --- /dev/null +++ b/lib/fog/aws/parsers/sns/list_subscriptions.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module SNS + class ListSubscriptions < Fog::Parsers::Base + def reset + @response = { 'Subscriptions' => [] } + @subscription = {} + end + + def end_element(name) + case name + when "TopicArn", "Protocol", "SubscriptionArn", "Owner", "Endpoint" + @subscription[name] = @value.strip + when "member" + @response['Subscriptions'] << @subscription + @subscription = {} + when 'RequestId', 'NextToken' + @response[name] = @value.strip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/list_topics.rb b/lib/fog/aws/parsers/sns/list_topics.rb new file mode 100644 index 000000000..40df34d32 --- /dev/null +++ b/lib/fog/aws/parsers/sns/list_topics.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SNS + class ListTopics < Fog::Parsers::Base + def reset + @response = { 'Topics' => [] } + end + + def end_element(name) + case name + when 'TopicArn' + @response['Topics'] << @value.strip + when 'NextToken', 'RequestId' + response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/publish.rb b/lib/fog/aws/parsers/sns/publish.rb new file mode 100644 index 000000000..68f69b338 --- /dev/null +++ b/lib/fog/aws/parsers/sns/publish.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class Publish < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'MessageId', 'RequestId' + @response[name] = @value.rstrip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/remove_permission.rb b/lib/fog/aws/parsers/sns/remove_permission.rb new file mode 100644 index 000000000..345c1f154 --- /dev/null +++ b/lib/fog/aws/parsers/sns/remove_permission.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class RemovePermission < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/set_topic_attributes.rb b/lib/fog/aws/parsers/sns/set_topic_attributes.rb new file mode 100644 index 000000000..e652e573a --- /dev/null +++ b/lib/fog/aws/parsers/sns/set_topic_attributes.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class SetTopicAttributes < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/subscribe.rb b/lib/fog/aws/parsers/sns/subscribe.rb new file mode 100644 index 000000000..9385404e3 --- /dev/null +++ b/lib/fog/aws/parsers/sns/subscribe.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class Subscribe < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'SubscriptionArn', 'RequestId' + @response[name] = @value.strip + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sns/unsubscribe.rb b/lib/fog/aws/parsers/sns/unsubscribe.rb new file mode 100644 index 000000000..5efd437aa --- /dev/null +++ b/lib/fog/aws/parsers/sns/unsubscribe.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SNS + class Unsubscribe < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sqs/basic.rb b/lib/fog/aws/parsers/sqs/basic.rb new file mode 100644 index 000000000..2ea4e2019 --- /dev/null +++ b/lib/fog/aws/parsers/sqs/basic.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module AWS + module SQS + class Basic < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sqs/create_queue.rb b/lib/fog/aws/parsers/sqs/create_queue.rb new file mode 100644 index 000000000..59614e139 --- /dev/null +++ b/lib/fog/aws/parsers/sqs/create_queue.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SQS + class CreateQueue < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = @value + when 'QueueUrl' + @response['QueueUrl'] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sqs/get_queue_attributes.rb b/lib/fog/aws/parsers/sqs/get_queue_attributes.rb new file mode 100644 index 000000000..50f078672 --- /dev/null +++ b/lib/fog/aws/parsers/sqs/get_queue_attributes.rb @@ -0,0 +1,31 @@ +module Fog + module Parsers + module AWS + module SQS + class GetQueueAttributes < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {}, 'Attributes' => {}} + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata']['RequestId'] = @value + when 'Name' + @current_attribute_name = @value + when 'Value' + case @current_attribute_name + when 'ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesNotVisible', 'MaximumMessageSize', 'MessageRetentionPeriod', 'VisibilityTimeout' + @response['Attributes'][@current_attribute_name] = @value.to_i + when 'CreatedTimestamp', 'LastModifiedTimestamp' + @response['Attributes'][@current_attribute_name] = Time.at(@value.to_i) + else + @response['Attributes'][@current_attribute_name] = @value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sqs/list_queues.rb b/lib/fog/aws/parsers/sqs/list_queues.rb new file mode 100644 index 000000000..0e47f37d6 --- /dev/null +++ b/lib/fog/aws/parsers/sqs/list_queues.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module SQS + class ListQueues < Fog::Parsers::Base + def reset + @response = { 'QueueUrls' => [], 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = @value + when 'QueueUrl' + @response['QueueUrls'] << @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sqs/receive_message.rb b/lib/fog/aws/parsers/sqs/receive_message.rb new file mode 100644 index 000000000..d39b693d1 --- /dev/null +++ b/lib/fog/aws/parsers/sqs/receive_message.rb @@ -0,0 +1,37 @@ +module Fog + module Parsers + module AWS + module SQS + class ReceiveMessage < Fog::Parsers::Base + def reset + @message = { 'Attributes' => {} } + @response = { 'ResponseMetadata' => {}, 'Message' => []} + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata']['RequestId'] = @value + when 'Message' + @response['Message'] << @message + @message = { 'Attributes' => {} } + when 'Body', 'MD5OfBody', 'MessageId', 'ReceiptHandle' + @message[name] = @value + when 'Name' + @current_attribute_name = @value + when 'Value' + case @current_attribute_name + when 'ApproximateFirstReceiveTimestamp', 'SentTimestamp' + @message['Attributes'][@current_attribute_name] = Time.at(@value.to_i / 1000.0) + when 'ApproximateReceiveCount' + @message['Attributes'][@current_attribute_name] = @value.to_i + else + @message['Attributes'][@current_attribute_name] = @value + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sqs/send_message.rb b/lib/fog/aws/parsers/sqs/send_message.rb new file mode 100644 index 000000000..e2ba08554 --- /dev/null +++ b/lib/fog/aws/parsers/sqs/send_message.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module SQS + class SendMessage < Fog::Parsers::Base + def reset + @response = { 'ResponseMetadata' => {} } + end + + def end_element(name) + case name + when 'RequestId' + @response['ResponseMetadata'][name] = @value + when 'MessageId' + @response['MessageId'] = @value + when 'MD5OfMessageBody' + @response['MD5OfMessageBody'] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/access_control_list.rb b/lib/fog/aws/parsers/storage/access_control_list.rb new file mode 100644 index 000000000..53247e1fa --- /dev/null +++ b/lib/fog/aws/parsers/storage/access_control_list.rb @@ -0,0 +1,42 @@ +module Fog + module Parsers + module Storage + module AWS + class AccessControlList < Fog::Parsers::Base + def reset + @in_access_control_list = false + @grant = { 'Grantee' => {} } + @response = { 'Owner' => {}, 'AccessControlList' => [] } + end + + def start_element(name, attrs = []) + super + if name == 'AccessControlList' + @in_access_control_list = true + end + end + + def end_element(name) + case name + when 'AccessControlList' + @in_access_control_list = false + when 'Grant' + @response['AccessControlList'] << @grant + @grant = { 'Grantee' => {} } + when 'DisplayName', 'ID' + if @in_access_control_list + @grant['Grantee'][name] = value + else + @response['Owner'][name] = value + end + when 'Permission' + @grant[name] = value + when 'URI' + @grant['Grantee'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/complete_multipart_upload.rb b/lib/fog/aws/parsers/storage/complete_multipart_upload.rb new file mode 100644 index 000000000..6c02c7175 --- /dev/null +++ b/lib/fog/aws/parsers/storage/complete_multipart_upload.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module Storage + module AWS + class CompleteMultipartUpload < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'Bucket', 'ETag', 'Key', 'Location', 'Code', 'Message' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/copy_object.rb b/lib/fog/aws/parsers/storage/copy_object.rb new file mode 100644 index 000000000..7223f4ae7 --- /dev/null +++ b/lib/fog/aws/parsers/storage/copy_object.rb @@ -0,0 +1,18 @@ +module Fog + module Parsers + module Storage + module AWS + class CopyObject < Fog::Parsers::Base + def end_element(name) + case name + when 'ETag' + @response[name] = value.gsub('"', '') + when 'LastModified' + @response[name] = Time.parse(value) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/cors_configuration.rb b/lib/fog/aws/parsers/storage/cors_configuration.rb new file mode 100644 index 000000000..f969feb5c --- /dev/null +++ b/lib/fog/aws/parsers/storage/cors_configuration.rb @@ -0,0 +1,38 @@ +module Fog + module Parsers + module Storage + module AWS + class CorsConfiguration < Fog::Parsers::Base + def reset + @in_cors_configuration_list = false + @cors_rule = {} + @response = { 'CORSConfiguration' => [] } + end + + def start_element(name, attrs = []) + super + if name == 'CORSConfiguration' + @in_cors_configuration_list = true + end + end + + def end_element(name) + case name + when 'CORSConfiguration' + @in_cors_configuration_list = false + when 'CORSRule' + @response['CORSConfiguration'] << @cors_rule + @cors_rule = {} + when 'MaxAgeSeconds' + @cors_rule[name] = value.to_i + when 'ID' + @cors_rule[name] = value + when 'AllowedOrigin', 'AllowedMethod', 'AllowedHeader', 'ExposeHeader' + (@cors_rule[name] ||= []) << value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/delete_multiple_objects.rb b/lib/fog/aws/parsers/storage/delete_multiple_objects.rb new file mode 100644 index 000000000..6d6198d7d --- /dev/null +++ b/lib/fog/aws/parsers/storage/delete_multiple_objects.rb @@ -0,0 +1,45 @@ +module Fog + module Parsers + module Storage + module AWS + class DeleteMultipleObjects < Fog::Parsers::Base + def reset + @deleted = { 'Deleted' => {} } + @error = { 'Error' => {} } + @response = { 'DeleteResult' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Deleted' + @in_deleted = true + end + end + + def end_element(name) + case name + when 'Deleted' + @response['DeleteResult'] << @deleted + @deleted = { 'Deleted' => {} } + @in_deleted = false + when 'Error' + @response['DeleteResult'] << @error + @error = { 'Error' => {} } + when 'Key', 'VersionId' + if @in_deleted + @deleted['Deleted'][name] = value + else + @error['Error'][name] = value + end + when 'DeleteMarker', 'DeletemarkerVersionId' + @deleted['Deleted'][name] = value + when 'Code', 'Message' + @error['Error'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket.rb b/lib/fog/aws/parsers/storage/get_bucket.rb new file mode 100644 index 000000000..0a98d306e --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket.rb @@ -0,0 +1,58 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucket < Fog::Parsers::Base + def reset + @object = { 'Owner' => {} } + @response = { 'Contents' => [], 'CommonPrefixes' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'CommonPrefixes' + @in_common_prefixes = true + end + end + + def end_element(name) + case name + when 'CommonPrefixes' + @in_common_prefixes = false + when 'Contents' + @response['Contents'] << @object + @object = { 'Owner' => {} } + when 'DisplayName', 'ID' + @object['Owner'][name] = value + when 'ETag' + @object[name] = value.gsub('"', '') + when 'IsTruncated' + if value == 'true' + @response['IsTruncated'] = true + else + @response['IsTruncated'] = false + end + when 'LastModified' + @object['LastModified'] = Time.parse(value) + when 'Marker', 'Name' + @response[name] = value + when 'MaxKeys' + @response['MaxKeys'] = value.to_i + when 'Prefix' + if @in_common_prefixes + @response['CommonPrefixes'] << value + else + @response[name] = value + end + when 'Size' + @object['Size'] = value.to_i + when 'Delimiter', 'Key', 'StorageClass' + @object[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb b/lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb new file mode 100644 index 000000000..ef9bc795d --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb @@ -0,0 +1,64 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucketLifecycle < Fog::Parsers::Base + def reset + @expiration = {} + @transition = {} + @rule = {} + @response = { 'Rules' => [] } + end + + def start_element(name, attrs=[]) + super + case name + when 'Expiration' + @in_expiration = true + when 'Transition' + @in_transition = true + end + end + + def end_element(name) + if @in_expiration + case name + when 'Days' + @expiration[name] = value.to_i + when 'Date' + @expiration[name] = value + when 'Expiration' + @rule['Expiration'] = @expiration + @in_expiration = false + @expiration = {} + end + elsif @in_transition + case name + when 'StorageClass', + @transition['StorageClass'] = value + when 'Date' + @transition[name] = value + when 'Days' + @transition[name] = value.to_i + when 'Transition' + @rule['Transition'] = @transition + @in_transition = false + @transition = {} + end + else + case name + when 'ID', 'Prefix' + @rule[name] = value + when 'Status' + @rule['Enabled'] = value == 'Enabled' + when 'Rule' + @response['Rules'] << @rule + @rule = {} + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_location.rb b/lib/fog/aws/parsers/storage/get_bucket_location.rb new file mode 100644 index 000000000..920f69761 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_location.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucketLocation < Fog::Parsers::Base + def end_element(name) + case name + when 'LocationConstraint' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_logging.rb b/lib/fog/aws/parsers/storage/get_bucket_logging.rb new file mode 100644 index 000000000..931aeaadb --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_logging.rb @@ -0,0 +1,36 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucketLogging < Fog::Parsers::Base + def reset + @grant = { 'Grantee' => {} } + @response = { 'BucketLoggingStatus' => {} } + end + + def end_element(name) + case name + when 'DisplayName', 'ID' + if @in_access_control_list + @grant['Grantee'][name] = value + else + @response['Owner'][name] = value + end + when 'Grant' + @response['BucketLoggingStatus']['LoggingEnabled']['TargetGrants'] << @grant + @grant = { 'Grantee' => {} } + when 'LoggingEnabled' + @response['BucketLoggingStatus']['LoggingEnabled'] = { 'TargetGrants' => [] } + when 'Permission' + @grant[name] = value + when 'TargetBucket', 'TargetPrefix' + @response['BucketLoggingStatus'][name] = value + when 'URI' + @grant['Grantee'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_object_versions.rb b/lib/fog/aws/parsers/storage/get_bucket_object_versions.rb new file mode 100644 index 000000000..dae2f2d47 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_object_versions.rb @@ -0,0 +1,84 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucketObjectVersions < Fog::Parsers::Base + def reset + @delete_marker = { 'Owner' => {} } + @version = { 'Owner' => {} } + + @in_delete_marke = false + @in_version = false + + @response = { 'Versions' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'DeleteMarker' + @in_delete_marker = true + when 'Version' + @in_version = true + end + end + + def end_element(name) + case name + when 'DeleteMarker' + @response['Versions'] << {'DeleteMarker' => @delete_marker } + @delete_marker = { 'Owner' => {} } + @in_delete_marker = false + when 'Version' + @response['Versions'] << {'Version' => @version } + @version = { 'Owner' => {} } + @in_version = false + when 'DisplayName', 'ID' + if @in_delete_marker + @delete_marker + elsif @in_version + @version + end['Owner'][name] = value + when 'ETag' + @version[name] = value.gsub('"', '') + when 'IsLatest' + if @in_delete_marker + @delete_marker + elsif @in_version + @version + end['IsLatest'] = if value == 'true' + true + else + false + end + when 'IsTruncated' + if value == 'true' + @response['IsTruncated'] = true + else + @response['IsTruncated'] = false + end + when 'LastModified' + if @in_delete_marker + @delete_marker + elsif @in_version + @version + end['LastModified'] = Time.parse(value) + when 'MaxKeys' + @response['MaxKeys'] = value.to_i + when 'Size' + @version['Size'] = value.to_i + when 'Key', 'KeyMarker', 'Name', 'NextKeyMarker', 'NextVersionIdMarker', 'Prefix', 'StorageClass', 'VersionId', 'VersionIdMarker' + if @in_delete_marker + @delete_marker + elsif @in_version + @version + else + @response + end[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_tagging.rb b/lib/fog/aws/parsers/storage/get_bucket_tagging.rb new file mode 100644 index 000000000..3b26b89c7 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_tagging.rb @@ -0,0 +1,33 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucketTagging < Fog::Parsers::Base + def reset + @in_tag = {} + @response = {'BucketTagging' => {}} + end + + def start_element(name, *args) + super + if name == 'Tag' + @in_tag = {} + end + end + + def end_element(name) + case name + when 'Tag' + @response['BucketTagging'].merge!(@in_tag) + @in_tag = {} + when 'Key' + @in_tag[value] = nil + when 'Value' + @in_tag = {@in_tag.keys.first => value} + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_versioning.rb b/lib/fog/aws/parsers/storage/get_bucket_versioning.rb new file mode 100644 index 000000000..549c6ebf4 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_versioning.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module Storage + module AWS + class GetBucketVersioning < Fog::Parsers::Base + def reset + @response = { 'VersioningConfiguration' => {} } + end + + def end_element(name) + case name + when 'Status', 'MfaDelete' + @response['VersioningConfiguration'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_bucket_website.rb b/lib/fog/aws/parsers/storage/get_bucket_website.rb new file mode 100644 index 000000000..1863ddeb9 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_website.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module Storage + module AWS + + # http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETwebsite.html + class GetBucketWebsite < Fog::Parsers::Base + def reset + @response = { 'ErrorDocument' => {}, 'IndexDocument' => {}, 'RedirectAllRequestsTo' => {} } + end + + def end_element(name) + case name + when 'Key' + @response['ErrorDocument'][name] = value + when 'Suffix' + @response['IndexDocument'][name] = value + when 'HostName' + @response['RedirectAllRequestsTo'][name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_request_payment.rb b/lib/fog/aws/parsers/storage/get_request_payment.rb new file mode 100644 index 000000000..91edb28ad --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_request_payment.rb @@ -0,0 +1,16 @@ +module Fog + module Parsers + module Storage + module AWS + class GetRequestPayment < Fog::Parsers::Base + def end_element(name) + case name + when 'Payer' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/get_service.rb b/lib/fog/aws/parsers/storage/get_service.rb new file mode 100644 index 000000000..403cb8188 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_service.rb @@ -0,0 +1,28 @@ +module Fog + module Parsers + module Storage + module AWS + class GetService < Fog::Parsers::Base + def reset + @bucket = {} + @response = { 'Owner' => {}, 'Buckets' => [] } + end + + def end_element(name) + case name + when 'Bucket' + @response['Buckets'] << @bucket + @bucket = {} + when 'CreationDate' + @bucket['CreationDate'] = Time.parse(value) + when 'DisplayName', 'ID' + @response['Owner'][name] = value + when 'Name' + @bucket[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/initiate_multipart_upload.rb b/lib/fog/aws/parsers/storage/initiate_multipart_upload.rb new file mode 100644 index 000000000..df5d66310 --- /dev/null +++ b/lib/fog/aws/parsers/storage/initiate_multipart_upload.rb @@ -0,0 +1,20 @@ +module Fog + module Parsers + module Storage + module AWS + class InitiateMultipartUpload < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'Bucket', 'Key', 'UploadId' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/list_multipart_uploads.rb b/lib/fog/aws/parsers/storage/list_multipart_uploads.rb new file mode 100644 index 000000000..0692f0074 --- /dev/null +++ b/lib/fog/aws/parsers/storage/list_multipart_uploads.rb @@ -0,0 +1,52 @@ +module Fog + module Parsers + module Storage + module AWS + class ListMultipartUploads < Fog::Parsers::Base + def reset + @upload = { 'Initiator' => {}, 'Owner' => {} } + @response = { 'Upload' => [] } + end + + def start_element(name, attrs = []) + super + case name + when 'Initiator' + @in_initiator = true + when 'Owner' + @in_owner = true + end + end + + def end_element(name) + case name + when 'Bucket', 'KeyMarker', 'NextKeyMarker', 'NextUploadIdMarker', 'UploadIdMarker' + @response[name] = value + when 'DisplayName', 'ID' + if @in_initiator + @upload['Initiator'][name] = value + elsif @in_owner + @upload['Owner'][name] = value + end + when 'Initiated' + @upload[name] = Time.parse(value) + when 'Initiator' + @in_initiator = false + when 'IsTruncated' + @response[name] = value == 'true' + when 'Key', 'StorageClass', 'UploadId' + @upload[name] = value + when 'MaxUploads' + @response[name] = value.to_i + when 'Owner' + @in_owner = false + when 'Upload' + @response['Upload'] << @upload + @upload = { 'Initiator' => {}, 'Owner' => {} } + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/storage/list_parts.rb b/lib/fog/aws/parsers/storage/list_parts.rb new file mode 100644 index 000000000..4cb6916f6 --- /dev/null +++ b/lib/fog/aws/parsers/storage/list_parts.rb @@ -0,0 +1,36 @@ +module Fog + module Parsers + module Storage + module AWS + class ListParts < Fog::Parsers::Base + def reset + @part = {} + @response = { 'Initiator' => {}, 'Part' => [] } + end + + def end_element(name) + case name + when 'Bucket', 'Key', 'NextPartNumberMarker', 'PartNumberMarker', 'StorageClass', 'UploadId' + @response[name] = value + when 'DisplayName', 'ID' + @response['Initiator'][name] = value + when 'ETag' + @part[name] = value + when 'IsTruncated' + @response[name] = value == 'true' + when 'LastModified' + @part[name] = Time.parse(value) + when 'MaxParts' + @response[name] = value.to_i + when 'Part' + @response['Part'] << @part + @part = {} + when 'PartNumber', 'Size' + @part[name] = value.to_i + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sts/assume_role.rb b/lib/fog/aws/parsers/sts/assume_role.rb new file mode 100644 index 000000000..f29a725fd --- /dev/null +++ b/lib/fog/aws/parsers/sts/assume_role.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module STS + class AssumeRole < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'SessionToken', 'SecretAccessKey', 'Expiration', 'AccessKeyId' + @response[name] = @value.strip + when 'Arn', 'AssumedRoleId' + @response[name] = @value.strip + when 'PackedPolicySize' + @response[name] = @value + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sts/assume_role_with_saml.rb b/lib/fog/aws/parsers/sts/assume_role_with_saml.rb new file mode 100644 index 000000000..34ade15b8 --- /dev/null +++ b/lib/fog/aws/parsers/sts/assume_role_with_saml.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module STS + class AssumeRoleWithSAML < Fog::Parsers::Base + def reset + @response = {} + end + + def end_element(name) + case name + when 'SessionToken', 'SecretAccessKey', 'Expiration', 'AccessKeyId' + @response[name] = @value.strip + when 'Arn', 'AssumedRoleId' + @response[name] = @value.strip + when 'PackedPolicySize' + @response[name] = @value + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/sts/get_session_token.rb b/lib/fog/aws/parsers/sts/get_session_token.rb new file mode 100644 index 000000000..cb57d2007 --- /dev/null +++ b/lib/fog/aws/parsers/sts/get_session_token.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module STS + class GetSessionToken < Fog::Parsers::Base + # http://docs.amazonwebservices.com/IAM/latest/UserGuide/index.html?CreatingFedTokens.html + + def reset + @response = {} + end + + def end_element(name) + case name + when 'SessionToken', 'SecretAccessKey', 'Expiration', 'AccessKeyId' + @response[name] = @value.strip + when 'Arn', 'FederatedUserId', 'PackedPolicySize' + @response[name] = @value.strip + when 'RequestId' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/rds.rb b/lib/fog/aws/rds.rb new file mode 100644 index 000000000..98d112ed0 --- /dev/null +++ b/lib/fog/aws/rds.rb @@ -0,0 +1,269 @@ +require 'fog/aws/core' + +module Fog + module AWS + class RDS < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class IdentifierTaken < Fog::Errors::Error; end + + class AuthorizationAlreadyExists < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :version, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/rds' + request :describe_events + request :create_db_instance + request :modify_db_instance + request :describe_db_instances + request :delete_db_instance + request :reboot_db_instance + request :create_db_instance_read_replica + request :describe_db_engine_versions + request :describe_db_reserved_instances + + request :add_tags_to_resource + request :list_tags_for_resource + request :remove_tags_from_resource + + request :describe_db_snapshots + request :create_db_snapshot + request :delete_db_snapshot + + request :create_db_parameter_group + request :delete_db_parameter_group + request :modify_db_parameter_group + request :describe_db_parameter_groups + + request :describe_db_security_groups + request :create_db_security_group + request :delete_db_security_group + request :authorize_db_security_group_ingress + request :revoke_db_security_group_ingress + + request :describe_db_parameters + + request :restore_db_instance_from_db_snapshot + request :restore_db_instance_to_point_in_time + + request :create_db_subnet_group + request :describe_db_subnet_groups + request :delete_db_subnet_group + # TODO: :modify_db_subnet_group + + request :describe_orderable_db_instance_options + + request :describe_db_log_files + request :download_db_logfile_portion + + request :promote_read_replica + + request :describe_event_subscriptions + request :create_event_subscription + request :delete_event_subscription + + model_path 'fog/aws/models/rds' + model :server + collection :servers + + model :snapshot + collection :snapshots + + model :parameter_group + collection :parameter_groups + + model :parameter + collection :parameters + + model :security_group + collection :security_groups + + model :subnet_group + collection :subnet_groups + + model :instance_option + collection :instance_options + + model :log_file + collection :log_files + + model :event_subscription + collection :event_subscriptions + + class Mock + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :servers => {}, + :security_groups => {}, + :subnet_groups => {}, + :snapshots => {}, + :event_subscriptions => {}, + :parameter_groups => { + "default.mysql5.1" => { + "DBParameterGroupFamily" => "mysql5.1", + "Description" => "Default parameter group for mysql5.1", + "DBParameterGroupName" => "default.mysql5.1" + }, + "default.mysql5.5" => { + "DBParameterGroupFamily" => "mysql5.5", + "Description" => "Default parameter group for mysql5.5", + "DBParameterGroupName" => "default.mysql5.5" + } + } + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @region = options[:region] || 'us-east-1' + + unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + attr_reader :region + + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to ELB + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # elb = ELB.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'eu-west-1', 'us-east-1' and etc. + # + # ==== Returns + # * ELB object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.rds' + @connection_options = options[:connection_options] || {} + + @region = options[:region] || 'us-east-1' + @host = options[:host] || "rds.#{@region}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + @version = options[:version] || '2013-05-15' + + setup_credentials(options) + end + + def owner_id + @owner_id ||= security_groups.get('default').owner_id + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'rds') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + {'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :aws_session_token => @aws_session_token, + :signer => @signer, + :host => @host, + :path => @path, + :port => @port, + :version => @version, + :method => 'POST' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + if match.empty? + case error.message + when 'Not Found' + raise Fog::AWS::RDS::NotFound.slurp(error, 'RDS Instance not found') + else + raise + end + else + raise case match[:code] + when 'DBInstanceNotFound', 'DBParameterGroupNotFound', 'DBSnapshotNotFound', 'DBSecurityGroupNotFound', 'SubscriptionNotFound' + Fog::AWS::RDS::NotFound.slurp(error, match[:message]) + when 'DBParameterGroupAlreadyExists' + Fog::AWS::RDS::IdentifierTaken.slurp(error, match[:message]) + when 'AuthorizationAlreadyExists' + Fog::AWS::RDS::AuthorizationAlreadyExists.slurp(error, match[:message]) + else + Fog::AWS::RDS::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end + end +end diff --git a/lib/fog/aws/redshift.rb b/lib/fog/aws/redshift.rb new file mode 100644 index 000000000..6dcfa31c6 --- /dev/null +++ b/lib/fog/aws/redshift.rb @@ -0,0 +1,133 @@ +require 'fog/aws/core' + +module Fog + module AWS + class Redshift < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/redshift' + + request :describe_clusters + request :describe_cluster_parameter_groups + request :describe_cluster_parameters + request :describe_cluster_security_groups + request :describe_cluster_snapshots + request :describe_cluster_subnet_groups + request :describe_cluster_versions + request :describe_default_cluster_parameters + request :describe_events + request :describe_orderable_cluster_options + request :describe_reserved_node_offerings + request :describe_reserved_nodes + request :describe_resize + request :create_cluster + request :create_cluster_parameter_group + request :create_cluster_security_group + request :create_cluster_snapshot + request :create_cluster_subnet_group + request :modify_cluster + request :modify_cluster_parameter_group + request :modify_cluster_subnet_group + request :delete_cluster + request :delete_cluster_parameter_group + request :delete_cluster_security_group + request :delete_cluster_snapshot + request :delete_cluster_subnet_group + request :authorize_cluster_security_group_ingress + request :authorize_snapshot_access + request :copy_cluster_snapshot + request :purchase_reserved_node_offering + request :reboot_cluster + request :reset_cluster_parameter_group + request :restore_from_cluster_snapshot + request :revoke_cluster_security_group_ingress + request :revoke_snapshot_access + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to Redshift + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # ses = SES.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'us-east-1' and etc. + # + # ==== Returns + # * Redshift object with connection to Aws. + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @region = options[:region] || 'us-east-1' + setup_credentials(options) + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.redshift' + @connection_options = options[:connection_options] || {} + @host = options[:host] || "redshift.#{@region}.amazonaws.com" + @version = '2012-12-01' + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + private + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key,@region,'redshift') + end + + def request(params, &block) + refresh_credentials_if_expired + + parser = params.delete(:parser) + date = Fog::Time.now + params[:headers]['Date'] = date.to_date_header + params[:headers]['x-amz-date'] = date.to_iso8601_basic + + params[:headers]['Host'] = @host + params[:headers]['x-amz-redshift-version'] = @version + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + params[:headers]['Authorization'] = @signer.sign params, date + params[:parser] = parser + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(params, &block) + end + else + _request(params, &block) + end + end + + def _request(params, &block) + @connection.request(params, &block) + end + end + end + end +end diff --git a/lib/fog/aws/region_methods.rb b/lib/fog/aws/region_methods.rb new file mode 100644 index 000000000..0dc3810a0 --- /dev/null +++ b/lib/fog/aws/region_methods.rb @@ -0,0 +1,11 @@ +module Fog + module AWS + module RegionMethods + def validate_aws_region host, region + if host.end_with?('.amazonaws.com') && !['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1', 'us-gov-west-1', 'eu-central-1'].include?(region) + raise ArgumentError, "Unknown region: #{region.inspect}" + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/create_auto_scaling_group.rb b/lib/fog/aws/requests/auto_scaling/create_auto_scaling_group.rb new file mode 100644 index 000000000..ad5b64a59 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/create_auto_scaling_group.rb @@ -0,0 +1,140 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Creates a new Auto Scaling group with the specified name. Once the + # creation request is completed, the AutoScalingGroup is ready to be + # used in other calls. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * availability_zones<~Array> - A list of availability zones for the + # Auto Scaling group. + # * launch_configuration_name<~String> - The name of the launch + # configuration to use with the Auto Scaling group. + # * max_size<~Integer> - The maximum size of the Auto Scaling group. + # * min_size<~Integer> - The minimum size of the Auto Scaling group. + # * options<~Hash>: + # * 'DefaultCooldown'<~Integer> - The amount of time, in seconds, + # after a scaling activity completes before any further trigger- + # related scaling activities can start. + # * 'DesiredCapacity'<~Integer> - The number of Amazon EC2 instances + # that should be running in the group. + # * 'HealthCheckGracePeriod'<~Integer> - Length of time in seconds + # after a new Amazon EC2 instance comes into service that Auto + # Scaling starts checking its health. + # * 'HealthCheckType'<~String> - The service you want the health + # status from, Amazon EC2 or Elastic Load Balancer. Valid values + # are "EC2" or "ELB". + # * 'LoadBalancerNames'<~Array> - A list of LoadBalancers to use. + # * 'PlacementGroup'<~String> - Physical location of your cluster + # placement group created in Amazon EC2. + # * 'Tags'<~Array>: + # * tag<~Hash>: + # * 'Key'<~String> - The key of the tag. + # * 'PropagateAtLaunch'<~Boolean> - Specifies whether the new tag + # will be applied to instances launched after the tag is + # created. The same behavior applies to updates: If you change + # a tag, the changed tag will be applied to all instances + # launched after you made the change. + # * 'ResourceId'<~String>: The name of the AutoScaling group. + # * 'ResourceType'<~String>: The kind of resource to which the + # tag is applied. Currently, Auto Scaling supports the + # auto-scaling-group resource type. + # * 'Value'<~String>: The value of the tag. + # * 'TerminationPolicies'<~Array> - A standalone termination policy + # or a list of termination policies used to select the instance to + # terminate. The policies are executed in the order that they are + # listed. + # * 'VPCZoneIdentifier'<~String> - A comma-separated list of subnet + # identifiers of Amazon Virtual Private Clouds (Amazon VPCs). + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_CreateAutoScalingGroup.html + # + + ExpectedOptions[:create_auto_scaling_group] = %w[DefaultCooldown DesiredCapacity HealthCheckGracePeriod HealthCheckType LoadBalancerNames PlacementGroup Tags TerminationPolicies VPCZoneIdentifier] + + def create_auto_scaling_group(auto_scaling_group_name, availability_zones, launch_configuration_name, max_size, min_size, options = {}) + options.merge!(Aws.indexed_param('AvailabilityZones.member.%d', [*availability_zones])) + options.delete('AvailabilityZones') + if load_balancer_names = options.delete('LoadBalancerNames') + options.merge!(Aws.indexed_param('LoadBalancerNames.member.%d', [*load_balancer_names])) + end + + if tags = options.delete('Tags') + tags.each_with_index do |(key, value), i| + options["Tags.member.#{i+1}.Key"] = key.to_s # turns symbol into string + options["Tags.member.#{i+1}.Value"] = value + end + end + if termination_policies = options.delete('TerminationPolicies') + options.merge!(Aws.indexed_param('TerminationPolicies.member.%d', [*termination_policies])) + end + + request({ + 'Action' => 'CreateAutoScalingGroup', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'LaunchConfigurationName' => launch_configuration_name, + 'MaxSize' => max_size, + 'MinSize' => min_size, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def create_auto_scaling_group(auto_scaling_group_name, availability_zones, launch_configuration_name, max_size, min_size, options = {}) + unexpected_options = options.keys - ExpectedOptions[:create_auto_scaling_group] + unless unexpected_options.empty? + raise Fog::AWS::AutoScaling::ValidationError.new("Options #{unexpected_options.join(',')} should not be included in request") + end + + if self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::IdentifierTaken.new("AutoScalingGroup by this name already exists - A group with the name #{auto_scaling_group_name} already exists") + end + unless self.data[:launch_configurations].key?(launch_configuration_name) + raise Fog::AWS::AutoScaling::ValidationError.new('Launch configuration name not found - null') + end + self.data[:auto_scaling_groups][auto_scaling_group_name] = { + 'AutoScalingGroupARN' => Fog::AWS::Mock.arn('autoscaling', self.data[:owner_id], "autoScalingGroup:00000000-0000-0000-0000-000000000000:autoScalingGroupName/#{auto_scaling_group_name}", @region), + 'AutoScalingGroupName' => auto_scaling_group_name, + 'AvailabilityZones' => [*availability_zones], + 'CreatedTime' => Time.now.utc, + 'DefaultCooldown' => 300, + 'DesiredCapacity' => 0, + 'EnabledMetrics' => [], + 'HealthCheckGracePeriod' => 0, + 'HealthCheckType' => 'EC2', + 'Instances' => [], + 'LaunchConfigurationName' => launch_configuration_name, + 'LoadBalancerNames' => [], + 'MaxSize' => max_size, + 'MinSize' => min_size, + 'PlacementGroup' => nil, + 'SuspendedProcesses' => [], + 'Tags' => [], + 'TerminationPolicies' => ['Default'], + 'VPCZoneIdentifier' => nil + }.merge!(options) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/create_launch_configuration.rb b/lib/fog/aws/requests/auto_scaling/create_launch_configuration.rb new file mode 100644 index 000000000..a3de444e1 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/create_launch_configuration.rb @@ -0,0 +1,114 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Creates a new launch configuration. When created, the new launch + # configuration is available for immediate use. + # + # ==== Parameters + # * image_id<~String> - Unique ID of the Amazon Machine Image (AMI) + # which was assigned during registration. + # * instance_type<~String> - The instance type of the EC2 instance. + # * launch_configuration_name<~String> - The name of the launch + # configuration to create. + # * options<~Hash>: + # * 'BlockDeviceMappings'<~Array>: + # * 'DeviceName'<~String> - The name of the device within Amazon + # EC2. + # * 'Ebs.SnapshotId'<~String> - The snapshot ID. + # * 'Ebs.VolumeSize'<~Integer> - The volume size, in GigaBytes. + # * 'VirtualName'<~String> - The virtual name associated with the + # device. + # * 'IamInstanceProfile'<~String> The name or the Amazon Resource + # Name (ARN) of the instance profile associated with the IAM role + # for the instance. + # * 'InstanceMonitoring.Enabled'<~Boolean> - Enables detailed + # monitoring, which is enabled by default. + # * 'KernelId'<~String> - The ID of the kernel associated with the + # Amazon EC2 AMI. + # * 'KeyName'<~String> - The name of the Amazon EC2 key pair. + # * 'RamdiskId'<~String> - The ID of the RAM disk associated with the + # Amazon EC2 AMI. + # * 'SecurityGroups'<~Array> - The names of the security groups with + # which to associate Amazon EC2 or Amazon VPC instances. + # * 'SpotPrice'<~String> - The maximum hourly price to be paid for + # any Spot Instance launched to fulfill the request. Spot Instances + # are launched when the price you specify exceeds the current Spot + # market price. + # * 'UserData'<~String> - The user data available to the launched + # Amazon EC2 instances. + # * 'EbsOptimized'<~Boolean> - Whether the instance is optimized for + # EBS I/O. Not required, default false. + # * 'PlacementTenancy'<~String> - The tenancy of the instance. Valid + # values: default | dedicated. Default: default + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_CreateLaunchConfiguration.html + # + def create_launch_configuration(image_id, instance_type, launch_configuration_name, options = {}) + if block_device_mappings = options.delete('BlockDeviceMappings') + block_device_mappings.each_with_index do |mapping, i| + for key, value in mapping + options.merge!({ format("BlockDeviceMappings.member.%d.#{key}", i+1) => value }) + end + end + end + if security_groups = options.delete('SecurityGroups') + options.merge!(Aws.indexed_param('SecurityGroups.member.%d', [*security_groups])) + end + if options['UserData'] + options['UserData'] = Base64.encode64(options['UserData']) + end + request({ + 'Action' => 'CreateLaunchConfiguration', + 'ImageId' => image_id, + 'InstanceType' => instance_type, + 'LaunchConfigurationName' => launch_configuration_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def create_launch_configuration(image_id, instance_type, launch_configuration_name, options = {}) + if self.data[:launch_configurations].key?(launch_configuration_name) + raise Fog::AWS::AutoScaling::IdentifierTaken.new("Launch Configuration by this name already exists - A launch configuration already exists with the name #{launch_configuration_name}") + end + self.data[:launch_configurations][launch_configuration_name] = { + 'AssociatePublicIpAddress' => nil, + 'BlockDeviceMappings' => [], + 'CreatedTime' => Time.now.utc, + 'EbsOptimized' => false, + 'IamInstanceProfile' => nil, + 'ImageId' => image_id, + 'InstanceMonitoring' => {'Enabled' => true}, + 'InstanceType' => instance_type, + 'KernelId' => nil, + 'KeyName' => nil, + 'LaunchConfigurationARN' => Fog::AWS::Mock.arn('autoscaling', self.data[:owner_id], "launchConfiguration:00000000-0000-0000-0000-000000000000:launchConfigurationName/#{launch_configuration_name}", @region), + 'LaunchConfigurationName' => launch_configuration_name, + 'PlacementTenancy' => nil, + 'RamdiskId' => nil, + 'SecurityGroups' => [], + 'UserData' => nil + }.merge!(options) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/create_or_update_tags.rb b/lib/fog/aws/requests/auto_scaling/create_or_update_tags.rb new file mode 100644 index 000000000..d102a8bd1 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/create_or_update_tags.rb @@ -0,0 +1,57 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Creates new tags or updates existing tags for an Auto Scaling group. + # + # ==== Parameters + # * tags<~Array>: + # * tag<~Hash>: + # * Key<~String> - The key of the tag. + # * PropagateAtLaunch<~Boolean> - Specifies whether the new tag + # will be applied to instances launched after the tag is created. + # The same behavior applies to updates: If you change a tag, the + # changed tag will be applied to all instances launched after you + # made the change. + # * ResourceId<~String> - The name of the Auto Scaling group. + # * ResourceType<~String> - The kind of resource to which the tag + # is applied. Currently, Auto Scaling supports the + # auto-scaling-group resource type. + # * Value<~String> - The value of the tag. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_CreateOrUpdateTags.html + # + def create_or_update_tags(tags) + params = {} + tags.each_with_index do |tag, i| + tag.each do |key, value| + params["Tags.member.#{i+1}.#{key}"] = value unless value.nil? + end + end + request({ + 'Action' => 'CreateOrUpdateTags', + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(params)) + end + end + + class Mock + def create_or_update_tags(tags) + if tags.to_a.empty? + raise Fog::AWS::AutoScaling::ValidationError.new("1 validation error detected: Value null at 'tags' failed to satisfy constraint: Member must not be null") + end + raise Fog::Mock::NotImplementedError + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/delete_auto_scaling_group.rb b/lib/fog/aws/requests/auto_scaling/delete_auto_scaling_group.rb new file mode 100644 index 000000000..d0493a81e --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/delete_auto_scaling_group.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Deletes the specified auto scaling group if the group has no + # instances and no scaling activities in progress. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * options<~Hash>: + # * 'ForceDelete'<~Boolean> - Starting with API version 2011-01-01, + # specifies that the Auto Scaling group will be deleted along with + # all instances associated with the group, without waiting for all + # instances to be terminated. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DeleteAutoScalingGroup.html + # + def delete_auto_scaling_group(auto_scaling_group_name, options = {}) + request({ + 'Action' => 'DeleteAutoScalingGroup', + 'AutoScalingGroupName' => auto_scaling_group_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def delete_auto_scaling_group(auto_scaling_group_name, options = {}) + unless self.data[:auto_scaling_groups].delete(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError, "The auto scaling group '#{auto_scaling_group_name}' does not exist." + end + + self.data[:notification_configurations].delete(auto_scaling_group_name) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/delete_launch_configuration.rb b/lib/fog/aws/requests/auto_scaling/delete_launch_configuration.rb new file mode 100644 index 000000000..753c537a0 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/delete_launch_configuration.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Deletes the specified launch configuration. + # + # The specified launch configuration must not be attached to an Auto + # Scaling group. Once this call completes, the launch configuration is + # no longer available for use. + # + # ==== Parameters + # * launch_configuration_name<~String> - The name of the launch + # configuration. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DeleteLaunchConfiguration.html + # + def delete_launch_configuration(launch_configuration_name) + request({ + 'Action' => 'DeleteLaunchConfiguration', + 'LaunchConfigurationName' => launch_configuration_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }) + end + end + + class Mock + def delete_launch_configuration(launch_configuration_name) + unless self.data[:launch_configurations].delete(launch_configuration_name) + raise Fog::AWS::AutoScaling::NotFound, "The launch configuration '#{launch_configuration_name}' does not exist." + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/delete_notification_configuration.rb b/lib/fog/aws/requests/auto_scaling/delete_notification_configuration.rb new file mode 100644 index 000000000..2c373432d --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/delete_notification_configuration.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Deletes notifications created by put_notification_configuration. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * topic_arn<~String> - The Amazon Resource Name (ARN) of the Amazon + # Simple Notification Service (SNS) topic. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DeleteNotificationConfiguration.html + # + def delete_notification_configuration(auto_scaling_group_name, topic_arn) + request({ + 'Action' => 'DeleteNotificationConfiguration', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'TopicARN' => topic_arn, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }) + end + end + + class Mock + def delete_notification_configuration(auto_scaling_group_name, topic_arn) + unless self.data[:notification_configurations].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError.new('AutoScalingGroup name not found - %s' % auto_scaling_group_name) + end + unless self.data[:notification_configurations][auto_scaling_group_name].key?(topic_arn) + raise Fog::AWS::AutoScaling::ValidationError.new("Notification Topic '#{topic_arn}' doesn't exist for '#{self.data[:owner_id]}'") + end + + self.data[:notification_configurations][auto_scaling_group_name].delete(topic_arn) + if self.data[:notification_configurations][auto_scaling_group_name].empty? + self.data[:notification_configurations].delete(auto_scaling_group_name) + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/delete_policy.rb b/lib/fog/aws/requests/auto_scaling/delete_policy.rb new file mode 100644 index 000000000..307a05cda --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/delete_policy.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Deletes a policy created by put_scaling_policy + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * policy_name<~String> - The name or PolicyARN of the policy you want + # to delete. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DeletePolicy.html + # + def delete_policy(auto_scaling_group_name, policy_name) + request({ + 'Action' => 'DeletePolicy', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'PolicyName' => policy_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }) + end + end + + class Mock + def delete_policy(auto_scaling_group_name, policy_name) + unless self.data[:scaling_policies].delete(policy_name) + raise Fog::AWS::AutoScaling::NotFound, "The scaling policy '#{policy_name}' does not exist." + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/delete_scheduled_action.rb b/lib/fog/aws/requests/auto_scaling/delete_scheduled_action.rb new file mode 100644 index 000000000..5e2b948fa --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/delete_scheduled_action.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Deletes a scheduled action previously created using the + # put_scheduled_update_group_action. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * scheduled_action_name<~String> - The name of the action you want to + # delete. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DeleteScheduledAction.html + # + def delete_scheduled_action(auto_scaling_group_name, scheduled_action_name) + request({ + 'Action' => 'DeleteScheduledAction', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'ScheduledActionName' => scheduled_action_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }) + end + end + + class Mock + def delete_scheduled_action(auto_scaling_group_name, scheduled_action_name) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/delete_tags.rb b/lib/fog/aws/requests/auto_scaling/delete_tags.rb new file mode 100644 index 000000000..cfe6dcfcb --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/delete_tags.rb @@ -0,0 +1,57 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Removes the specified tags or a set of tags from a set of resources. + # + # ==== Parameters + # * tags<~Array>: + # * tag<~Hash>: + # * Key<~String> - The key of the tag. + # * PropagateAtLaunch<~Boolean> - Specifies whether the new tag + # will be applied to instances launched after the tag is created. + # The same behavior applies to updates: If you change a tag, the + # changed tag will be applied to all instances launched after you + # made the change. + # * ResourceId<~String> - The name of the Auto Scaling group. + # * ResourceType<~String> - The kind of resource to which the tag + # is applied. Currently, Auto Scaling supports the + # auto-scaling-group resource type. + # * Value<~String> - The value of the tag. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DeleteTags.html + # + def delete_tags(tags) + params = {} + tags.each_with_index do |tag, i| + tag.each do |key, value| + params["Tags.member.#{i+1}.#{key}"] = value unless value.nil? + end + end + request({ + 'Action' => 'DeleteTags', + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(params)) + end + end + + class Mock + def delete_tags(tags) + if tags.to_a.empty? + raise Fog::AWS::AutoScaling::ValidationError.new("1 validation error detected: Value null at 'tags' failed to satisfy constraint: Member must not be null") + end + raise Fog::Mock::NotImplementedError + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_adjustment_types.rb b/lib/fog/aws/requests/auto_scaling/describe_adjustment_types.rb new file mode 100644 index 000000000..602abad9b --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_adjustment_types.rb @@ -0,0 +1,48 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_adjustment_types' + + # Returns policy adjustment types for use in the put_scaling_policy + # action. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeAdjustmentTypesResponse'<~Hash>: + # * 'AdjustmentTypes'<~Array>: + # * 'AdjustmentType'<~String> - A policy adjustment type. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeAdjustmentTypes.html + # + def describe_adjustment_types() + request({ + 'Action' => 'DescribeAdjustmentTypes', + :idempotent => true, + :parser => Fog::Parsers::AWS::AutoScaling::DescribeAdjustmentTypes.new + }) + end + end + + class Mock + def describe_adjustment_types() + results = { 'AdjustmentTypes' => [] } + self.data[:adjustment_types].each do |adjustment_type| + results['AdjustmentTypes'] << { 'AdjustmentType' => adjustment_type } + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeAdjustmentTypesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_groups.rb b/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_groups.rb new file mode 100644 index 000000000..1f7c80140 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_groups.rb @@ -0,0 +1,134 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_auto_scaling_groups' + + # Returns a full description of each Auto Scaling group in the given + # list. This includes all Amazon EC2 instances that are members of the + # group. If a list of names is not provided, the service returns the + # full details of all Auto Scaling groups. + # + # This action supports pagination by returning a token if there are + # more pages to retrieve. To get the next page, call this action again + # with the returned token as the NextToken parameter. + # + # ==== Parameters + # * options<~Hash>: + # * 'AutoScalingGroupNames'<~Array> - A list of Auto Scaling group + # names. + # * 'MaxRecords'<~Integer> - The maximum number of records to return. + # * 'NextToken'<~String> - A string that marks the start of the next + # batch of returned results. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeAutoScalingGroupsResponse'<~Hash>: + # * 'AutoScalingGroups'<~Array>: + # * 'AutoScalingGroup'<~Hash>: + # * 'AutoScalingGroupARN'<~String> - The Amazon Resource Name + # (ARN) of the Auto Scaling group. + # * 'AutoScalingGroupName'<~String> - Specifies the name of + # the group. + # * 'AvailabilityZones'<~Array> - Contains a list of + # availability zones for the group. + # * 'CreatedTime'<~Time> - Specifies the date and time the + # Auto Scaling group was created. + # * 'DefaultCooldown'<~Integer> - The number of seconds after + # a scaling activity completes before any further scaling + # activities can start. + # * 'DesiredCapacity'<~Integer> - Specifies the desired + # capacity of the Auto Scaling group. + # * 'EnabledMetrics'<~Array>: + # * enabledmetric<~Hash>: + # * 'Granularity'<~String> - The granularity of the + # enabled metric. + # * 'Metrics'<~String> - The name of the enabled metric. + # * 'HealthCheckGracePeriod'<~Integer>: The length of time + # that Auto Scaling waits before checking an instance's + # health status. The grace period begins when an instance + # comes into service. + # * 'HealthCheckType'<~String>: The service of interest for + # the health status check, either "EC2" for Amazon EC2 or + # "ELB" for Elastic Load Balancing. + # * 'Instances'<~Array>: + # * instance<~Hash>: + # * 'AvailabilityZone'<~String>: Availability zone + # associated with this instance. + # * 'HealthStatus'<~String>: The instance's health + # status. + # * 'InstanceId'<~String>: Specifies the EC2 instance ID. + # * 'LaunchConfigurationName'<~String>: The launch + # configuration associated with this instance. + # * 'LifecycleState'<~String>: Contains a description of + # the current lifecycle state. + # * 'LaunchConfigurationName'<~String> - Specifies the name + # of the associated launch configuration. + # * 'LoadBalancerNames'<~Array> - A list of load balancers + # associated with this Auto Scaling group. + # * 'MaxSize'<~Integer> - The maximum size of the Auto + # Scaling group. + # * 'MinSize'<~Integer> - The minimum size of the Auto + # Scaling group. + # * 'PlacementGroup'<~String> - The name of the cluster + # placement group, if applicable. + # * 'SuspendedProcesses'<~Array>: + # * suspendedprocess'<~Hash>: + # * 'ProcessName'<~String> - The name of the suspended + # process. + # * 'SuspensionReason'<~String> - The reason that the + # process was suspended. + # * 'TerminationPolicies'<~Array> - A standalone termination + # policy or a list of termination policies for this Auto + # Scaling group. + # * 'VPCZoneIdentifier'<~String> - The subnet identifier for + # the Amazon VPC connection, if applicable. You can specify + # several subnets in a comma-separated list. + # * 'NextToken'<~String> - A string that marks the start of the + # next batch of returned results. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeAutoScalingGroups.html + # + def describe_auto_scaling_groups(options = {}) + if auto_scaling_group_names = options.delete('AutoScalingGroupNames') + options.merge!(Aws.indexed_param('AutoScalingGroupNames.member.%d', [*auto_scaling_group_names])) + end + request({ + 'Action' => 'DescribeAutoScalingGroups', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeAutoScalingGroups.new + }.merge!(options)) + end + end + + class Mock + def describe_auto_scaling_groups(options = {}) + results = { 'AutoScalingGroups' => [] } + asg_set = self.data[:auto_scaling_groups] + + if !options["AutoScalingGroupNames"].nil? + asg_set = asg_set.reject do |asg_name, asg_data| + ![*options["AutoScalingGroupNames"]].include?(asg_name) + end + end + + asg_set.each do |asg_name, asg_data| + results['AutoScalingGroups'] << { + 'AutoScalingGroupName' => asg_name + }.merge!(asg_data) + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeAutoScalingGroupsResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_instances.rb b/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_instances.rb new file mode 100644 index 000000000..de258366e --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_instances.rb @@ -0,0 +1,89 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_auto_scaling_instances' + + # Returns a description of each Auto Scaling instance in the + # instance_ids list. If a list is not provided, the service returns the + # full details of all instances. + # + # This action supports pagination by returning a token if there are + # more pages to retrieve. To get the next page, call this action again + # with the returned token as the NextToken parameter. + # + # ==== Parameters + # * options<~Hash>: + # * 'InstanceIds'<~Array> - The list of Auto Scaling instances to + # describe. If this list is omitted, all auto scaling instances are + # described. The list of requested instances cannot contain more + # than 50 items. If unknown instances are requested, they are + # ignored with no error. + # * 'MaxRecords'<~Integer> - The aximum number of Auto Scaling + # instances to be described with each call. + # * 'NextToken'<~String> - The token returned by a previous call to + # indicate that there is more data available. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeAutoScalingInstancesResponse'<~Hash>: + # * 'AutoScalingInstances'<~Array>: + # * autoscalinginstancedetails<~Hash>: + # * 'AutoScalingGroupName'<~String> - The name of the Auto + # Scaling Group associated with this instance. + # * 'AvailabilityZone'<~String> - The availability zone in + # which this instance resides. + # * 'HealthStatus'<~String> - The health status of this + # instance. "Healthy" means that the instance is healthy + # and should remain in service. "Unhealthy" means that the + # instance is unhealthy. Auto Scaling should terminate and + # replace it. + # * 'InstanceId'<~String> - The instance's EC2 instance ID. + # * 'LaunchConfigurationName'<~String> - The launch + # configuration associated with this instance. + # * 'LifecycleState'<~String> - The life cycle state of this + # instance. + # * 'NextToken'<~String> - Acts as a paging mechanism for large + # result sets. Set to a non-empty string if there are + # additional results waiting to be returned. Pass this in to + # subsequent calls to return additional results. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeAutoScalingInstances.html + # + def describe_auto_scaling_instances(options = {}) + if instance_ids = options.delete('InstanceIds') + options.merge!(Aws.indexed_param('InstanceIds.member.%d', [*instance_ids])) + end + request({ + 'Action' => 'DescribeAutoScalingInstances', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeAutoScalingInstances.new + }.merge!(options)) + end + end + + class Mock + def describe_auto_scaling_instances(options = {}) + results = { 'AutoScalingInstances' => [] } + self.data[:auto_scaling_groups].each do |asg_name, asg_data| + asg_data['Instances'].each do |instance| + results['AutoScalingInstances'] << { + 'AutoScalingGroupName' => asg_name + }.merge!(instance) + end + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeAutoScalingInstancesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_notification_types.rb b/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_notification_types.rb new file mode 100644 index 000000000..8764e71dd --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_auto_scaling_notification_types.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_auto_scaling_notification_types' + + # Returns a list of all notification types that are supported by Auto + # Scaling. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeAutoScalingNotificationTypesResult'<~Hash>: + # * 'AutoScalingNotificationTypes'<~Array>: + # * 'notificationType'<~String> - A notification type. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeAutoScalingNotificationTypes.html + # + def describe_auto_scaling_notification_types() + request({ + 'Action' => 'DescribeAutoScalingNotificationTypes', + :idempotent => true, + :parser => Fog::Parsers::AWS::AutoScaling::DescribeAutoScalingNotificationTypes.new + }) + end + end + + class Mock + def describe_auto_scaling_notification_types() + results = { + 'AutoScalingNotificationTypes' => [], + } + self.data[:notification_types].each do |notification_type| + results['AutoScalingNotificationTypes'] << notification_type + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeAutoScalingNotificationTypesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_launch_configurations.rb b/lib/fog/aws/requests/auto_scaling/describe_launch_configurations.rb new file mode 100644 index 000000000..4f9b69045 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_launch_configurations.rb @@ -0,0 +1,112 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_launch_configurations' + + # Returns a full description of the launch configurations given the + # specified names. + # + # If no names are specified, then the full details of all launch + # configurations are returned. + # + # ==== Parameters + # * options<~Hash>: + # * 'LaunchConfigurationNames'<~Array> - A list of launch + # configuration names. + # * 'MaxRecords'<~Integer> - The maximum number of launch + # configurations. + # * 'NextToken'<~String> - The token returned by a previous call to + # indicate that there is more data available. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeLaunchConfigurationsResponse'<~Hash>: + # * 'LaunchConfigurations'<~Array>: + # * launchconfiguration'<~Hash>: + # * 'BlockDeviceMappings'<~Array>: + # * blockdevicemapping<~Hash>: + # * 'DeviceName'<~String> - The name of the device within + # EC2. + # * 'Ebs'<~Hash>: + # * 'SnapshotId'<~String> - The snapshot ID + # * 'VolumeSize'<~Integer> - The volume size, in + # GigaBytes. + # * 'VirtualName'<~String> - The virtual name associated + # with the device. + # * 'CreatedTime'<~Time> - Provides the creation date and + # time for this launch configuration. + # * 'ImageId'<~String> - Provides the unique ID of the Amazon + # Machine Image (AMI) that was assigned during + # registration. + # * 'InstanceMonitoring'<~Hash>: + # * 'Enabled'<~Boolean> - If true, instance monitoring is + # enabled. + # * 'InstanceType'<~String> - Specifies the instance type of + # the EC2 instance. + # * 'KernelId'<~String> - Provides the ID of the kernel + # associated with the EC2 AMI. + # * 'KeyName'<~String> - Provides the name of the EC2 key + # pair. + # * 'LaunchConfigurationARN'<~String> - The launch + # configuration's Amazon Resource Name (ARN). + # * 'LaunchConfigurationName'<~String> - Specifies the name + # of the launch configuration. + # * 'RamdiskId'<~String> - Provides ID of the RAM disk + # associated with the EC2 AMI. + # * 'PlacementTenancy'<~String> - The tenancy of the instance. + # * 'SecurityGroups'<~Array> - A description of the security + # groups to associate with the EC2 instances. + # * 'UserData'<~String> - The user data available to the + # launched EC2 instances. + # * 'NextToken'<~String> - Acts as a paging mechanism for large + # result sets. Set to a non-empty string if there are + # additional results waiting to be returned. Pass this in to + # subsequent calls to return additional results. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeLaunchConfigurations.html + # + def describe_launch_configurations(options = {}) + if launch_configuration_names = options.delete('LaunchConfigurationNames') + options.merge!(Aws.indexed_param('LaunchConfigurationNames.member.%d', [*launch_configuration_names])) + end + request({ + 'Action' => 'DescribeLaunchConfigurations', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeLaunchConfigurations.new + }.merge!(options)) + end + end + + class Mock + def describe_launch_configurations(options = {}) + launch_configuration_names = options.delete('LaunchConfigurationNames') + # even a nil object will turn into an empty array + lc = [*launch_configuration_names] + + launch_configurations = + if lc.any? + lc.map do |lc_name| + l_conf = self.data[:launch_configurations].find { |name, data| name == lc_name } + #raise Fog::AWS::AutoScaling::NotFound unless l_conf + l_conf[1].dup if l_conf + end.compact + else + self.data[:launch_configurations].map { |lc, values| values.dup } + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeLaunchConfigurationsResult' => { 'LaunchConfigurations' => launch_configurations }, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_metric_collection_types.rb b/lib/fog/aws/requests/auto_scaling/describe_metric_collection_types.rb new file mode 100644 index 000000000..dd100857d --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_metric_collection_types.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_metric_collection_types' + + # Returns a list of metrics and a corresponding list of granularities + # for each metric. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeMetricCollectionTypesResult'<~Hash>: + # * 'Granularities'<~Array>: + # * 'Granularity'<~String> - The granularity of a Metric. + # * 'Metrics'<~Array>: + # * 'Metric'<~String> - The name of a Metric. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeMetricCollectionTypes.html + # + def describe_metric_collection_types() + request({ + 'Action' => 'DescribeMetricCollectionTypes', + :idempotent => true, + :parser => Fog::Parsers::AWS::AutoScaling::DescribeMetricCollectionTypes.new + }) + end + end + + class Mock + def describe_metric_collection_types() + results = { + 'Granularities' => [], + 'Metrics' => [] + } + self.data[:metric_collection_types][:granularities].each do |granularity| + results['Granularities'] << { 'Granularity' => granularity } + end + self.data[:metric_collection_types][:metrics].each do |metric| + results['Metrics'] << { 'Metric' => metric } + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeMetricCollectionTypesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_notification_configurations.rb b/lib/fog/aws/requests/auto_scaling/describe_notification_configurations.rb new file mode 100644 index 000000000..9f67bfe85 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_notification_configurations.rb @@ -0,0 +1,73 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_notification_configurations' + + # Returns a list of notification actions associated with Auto Scaling + # groups for specified events. + # + # ==== Parameters + # * options<~Hash>: + # * 'AutoScalingGroupNames'<~String> - The name of the Auto Scaling + # group. + # * 'MaxRecords'<~Integer> - The maximum number of records to return. + # * 'NextToken'<~String> - A string that is used to mark the start of + # the next batch of returned results for pagination. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeNotificationConfigurationsResult'<~Hash>: + # * 'NotificationConfigurations'<~Array>: + # * notificationConfiguration<~Hash>: + # * 'AutoScalingGroupName'<~String> - Specifies the Auto + # Scaling group name. + # * 'NotificationType'<~String> - The types of events for an + # action to start. + # * 'TopicARN'<~String> - The Amazon Resource Name (ARN) of the + # Amazon Simple Notification Service (SNS) topic. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeNotificationConfigurations.html + # + def describe_notification_configurations(options = {}) + if auto_scaling_group_names = options.delete('AutoScalingGroupNames') + options.merge!(Aws.indexed_param('AutoScalingGroupNames.member.%d', [*auto_scaling_group_names])) + end + request({ + 'Action' => 'DescribeNotificationConfigurations', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeNotificationConfigurations.new + }.merge!(options)) + end + end + + class Mock + def describe_notification_configurations(options = {}) + results = { 'NotificationConfigurations' => [] } + (options['AutoScalingGroupNames']||self.data[:notification_configurations].keys).each do |asg_name| + (self.data[:notification_configurations][asg_name]||{}).each do |topic_arn, notification_types| + notification_types.each do |notification_type| + results['NotificationConfigurations'] << { + 'AutoScalingGroupName' => asg_name, + 'NotificationType' => notification_type, + 'TopicARN' => topic_arn, + } + end + end + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeNotificationConfigurationsResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_policies.rb b/lib/fog/aws/requests/auto_scaling/describe_policies.rb new file mode 100644 index 000000000..fe7af0abd --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_policies.rb @@ -0,0 +1,105 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_policies' + + # Returns descriptions of what each policy does. This action supports + # pagination. If the response includes a token, there are more records + # available. To get the additional records, repeat the request with the + # response token as the NextToken parameter. + # + # ==== Parameters + # * options<~Hash>: + # * 'AutoScalingGroupName'<~String> - The name of the Auto Scaling + # group. + # * 'MaxRecords'<~Integer> - The maximum number of policies that will + # be described with each call. + # * 'NextToken'<~String> - The token returned by a previous call to + # indicate that there is more data available. + # * PolicyNames<~Array> - A list of policy names or policy ARNs to be + # described. If this list is omitted, all policy names are + # described. If an auto scaling group name is provided, the results + # are limited to that group.The list of requested policy names + # cannot contain more than 50 items. If unknown policy names are + # requested, they are ignored with no error. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribePoliciesResult'<~Hash>: + # * 'ScalingPolicies'<~Array>: + # * 'AdjustmentType'<~String> - Specifies whether the + # adjustment is an absolute number or a percentage of the + # current capacity. + # * 'Alarms'<~Array>: + # * 'AlarmARN'<~String> - The Amazon Resource Name (ARN) of + # the alarm. + # * 'AlarmName'<~String> - The name of the alarm. + # * 'AutoScalingGroupName'<~String> - The name of the Auto + # Scaling group associated with this scaling policy. + # * 'Cooldown'<~Integer> - The amount of time, in seconds, + # after a scaling activity completes before any further + # trigger-related scaling activities can start. + # * 'PolicyARN'<~String> - The Amazon Resource Name (ARN) of + # the policy. + # * 'PolicyName'<~String> - The name of the scaling policy. + # * 'ScalingAdjustment'<~Integer> - The number associated with + # the specified AdjustmentType. A positive value adds to the + # current capacity and a negative value removes from the + # current capacity. + # * 'NextToken'<~String> - Acts as a paging mechanism for large + # result sets. Set to a non-empty string if there are + # additional results waiting to be returned. Pass this in to + # subsequent calls to return additional results. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribePolicies.html + # + def describe_policies(options = {}) + if policy_names = options.delete('PolicyNames') + options.merge!(Aws.indexed_param('PolicyNames.member.%d', [*policy_names])) + end + request({ + 'Action' => 'DescribePolicies', + :parser => Fog::Parsers::AWS::AutoScaling::DescribePolicies.new + }.merge!(options)) + end + end + + class Mock + def describe_policies(options = {}) + results = { 'ScalingPolicies' => [] } + policy_set = self.data[:scaling_policies] + + for opt_key, opt_value in options + if opt_key == "PolicyNames" && opt_value != nil && opt_value != "" + policy_set = policy_set.reject do |asp_name, asp_data| + ![*options["PolicyNames"]].include?(asp_name) + end + elsif opt_key == "AutoScalingGroupName" && opt_value != nil && opt_value != "" + policy_set = policy_set.reject do |asp_name, asp_data| + options["AutoScalingGroupName"] != asp_data["AutoScalingGroupName"] + end + end + end + + policy_set.each do |asp_name, asp_data| + results['ScalingPolicies'] << { + 'PolicyName' => asp_name + }.merge!(asp_data) + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribePoliciesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_scaling_activities.rb b/lib/fog/aws/requests/auto_scaling/describe_scaling_activities.rb new file mode 100644 index 000000000..a91a17abe --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_scaling_activities.rb @@ -0,0 +1,82 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_scaling_activities' + + # Returns the scaling activities for the specified Auto Scaling group. + # + # If the specified activity_ids list is empty, all the activities from + # the past six weeks are returned. Activities are sorted by completion + # time. Activities still in progress appear first on the list. + # + # This action supports pagination. If the response includes a token, + # there are more records available. To get the additional records, + # repeat the request with the response token as the NextToken + # parameter. + # + # ==== Parameters + # * options<~Hash>: + # * 'ActivityIds'<~Array> - A list containing the activity IDs of the + # desired scaling activities. If this list is omitted, all + # activities are described. If an AutoScalingGroupName is provided, + # the results are limited to that group. The list of requested + # activities cannot contain more than 50 items. If unknown + # activities are requested, they are ignored with no error. + # * 'AutoScalingGroupName'<~String> - The name of the Auto Scaling + # group. + # * 'MaxRecords'<~Integer> - The maximum number of scaling activities + # to return. + # * 'NextToken'<~String> - The token returned by a previous call to + # indicate that there is more data available. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeScalingActivitiesResponse'<~Hash>: + # * 'Activities'<~Array>: + # * 'ActivityId'<~String> - Specifies the ID of the activity. + # * 'AutoScalingGroupName'<~String> - The name of the Auto + # Scaling group. + # * 'Cause'<~String> - Contins the reason the activity was + # begun. + # * 'Description'<~String> - Contains a friendly, more verbose + # description of the scaling activity. + # * 'EndTime'<~Time> - Provides the end time of this activity. + # * 'Progress'<~Integer> - Specifies a value between 0 and 100 + # that indicates the progress of the activity. + # * 'StartTime'<~Time> - Provides the start time of this + # activity. + # * 'StatusCode'<~String> - Contains the current status of the + # activity. + # * 'StatusMessage'<~String> - Contains a friendly, more + # verbose description of the activity status. + # * 'NextToken'<~String> - Acts as a paging mechanism for large + # result sets. Set to a non-empty string if there are + # additional results waiting to be returned. Pass this in to + # subsequent calls to return additional results. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeScalingActivities.html + # + def describe_scaling_activities(options = {}) + if activity_ids = options.delete('ActivityIds') + options.merge!(Aws.indexed_param('ActivityIds.member.%d', [*activity_ids])) + end + request({ + 'Action' => 'DescribeScalingActivities', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeScalingActivities.new + }.merge!(options)) + end + end + + class Mock + def describe_scaling_activities(options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_scaling_process_types.rb b/lib/fog/aws/requests/auto_scaling/describe_scaling_process_types.rb new file mode 100644 index 000000000..63170a71a --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_scaling_process_types.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_scaling_process_types' + + # Returns scaling process types for use in the resume_processes and + # suspend_processes actions. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeScalingProcessTypesResult'<~Hash>: + # * 'Processes'<~Array>: + # * processtype<~Hash>: + # * 'ProcessName'<~String> - The name of a process. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeScalingProcessTypes.html + # + def describe_scaling_process_types() + request({ + 'Action' => 'DescribeScalingProcessTypes', + :idempotent => true, + :parser => Fog::Parsers::AWS::AutoScaling::DescribeScalingProcessTypes.new + }) + end + end + + class Mock + def describe_scaling_process_types() + results = { 'Processes' => [] } + self.data[:process_types].each do |process_type| + results['Processes'] << { 'ProcessName' => process_type } + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeScalingProcessTypesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_scheduled_actions.rb b/lib/fog/aws/requests/auto_scaling/describe_scheduled_actions.rb new file mode 100644 index 000000000..5b4e52145 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_scheduled_actions.rb @@ -0,0 +1,82 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_scheduled_actions' + + # List all the actions scheduled for your Auto Scaling group that + # haven't been executed. To see a list of action already executed, see + # the activity record returned in describe_scaling_activities. + # + # ==== Parameters + # * options<~Hash>: + # * 'AutoScalingGroupName'<~String> - The name of the Auto Scaling + # group. + # * 'EndTime'<~Time> - The latest scheduled start time to return. If + # scheduled action names are provided, this field will be ignored. + # * 'MaxRecords'<~Integer> - The maximum number of scheduled actions + # to return. + # * 'NextToken'<~String> - The token returned by a previous call to + # indicate that there is more data available. + # * 'ScheduledActionNames'<~Array> - A list of scheduled actions to + # be described. If this list is omitted, all scheduled actions are + # described. The list of requested scheduled actions cannot contain + # more than 50 items. If an auto scaling group name is provided, + # the results are limited to that group. If unknown scheduled + # actions are requested, they are ignored with no error. + # * 'StartTime'<~Time> - The earliest scheduled start time to return. + # If scheduled action names are provided, this field will be + # ignored. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeScheduledActionsResponse'<~Hash>: + # * 'ScheduledUpdateGroupActions'<~Array>: + # * scheduledupdatesroupAction<~Hash>: + # * 'AutoScalingGroupName'<~String> - The name of the Auto + # Scaling group to be updated. + # * 'DesiredCapacity'<~Integer> -The number of instances you + # prefer to maintain in your Auto Scaling group. + # * 'EndTime'<~Time> - The time for this action to end. + # * 'MaxSize'<~Integer> - The maximum size of the Auto Scaling + # group. + # * 'MinSize'<~Integer> - The minimum size of the Auto Scaling + # group. + # * 'Recurrence'<~String> - The time when recurring future + # actions will start. Start time is specified by the user + # following the Unix cron syntax format. + # * 'ScheduledActionARN'<~String> - The Amazon Resource Name + # (ARN) of this scheduled action. + # * 'StartTime'<~Time> - The time for this action to start. + # * 'Time'<~Time> - The time that the action is scheduled to + # occur. This value can be up to one month in the future. + # * 'NextToken'<~String> - Acts as a paging mechanism for large + # result sets. Set to a non-empty string if there are + # additional results waiting to be returned. Pass this in to + # subsequent calls to return additional results. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeScheduledActions.html + # + def describe_scheduled_actions(options = {}) + if scheduled_action_names = options.delete('ScheduledActionNames') + options.merge!(Aws.indexed_param('ScheduledActionNames.member.%d', [*scheduled_action_names])) + end + request({ + 'Action' => 'DescribeScheduledActions', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeScheduledActions.new + }.merge!(options)) + end + end + + class Mock + def describe_scheduled_actions(options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_tags.rb b/lib/fog/aws/requests/auto_scaling/describe_tags.rb new file mode 100644 index 000000000..e20bdc41b --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_tags.rb @@ -0,0 +1,68 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_tags' + + # Lists the Auto Scaling group tags. + # + # ==== Parameters + # * options<~Hash>: + # * tag<~Hash>: + # * Key<~String> - The key of the tag. + # * PropagateAtLaunch<~Boolean> - Specifies whether the new tag + # will be applied to instances launched after the tag is created. + # The same behavior applies to updates: If you change a tag, + # changed tag will be applied to all instances launched after you + # made the change. + # * ResourceId<~String> - The name of the Auto Scaling group. + # * ResourceType<~String> - The kind of resource to which the tag + # is applied. Currently, Auto Scaling supports the + # auto-scaling-group resource type. + # * Value<~String> - The value of the tag. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeTagsResult'<~Hash>: + # * 'NextToken'<~String> - A string used to mark the start of the + # next batch of returned results. + # * 'Tags'<~Hash>: + # * tagDescription<~Hash>: + # * 'Key'<~String> - The key of the tag. + # * 'PropagateAtLaunch'<~Boolean> - Specifies whether the new + # tag will be applied to instances launched after the tag + # is created. The same behavior applies to updates: If you + # change a tag, the changed tag will be applied to all + # instances launched after you made the change. + # * 'ResourceId'<~String> - The name of the Auto Scaling + # group. + # * 'ResourceType'<~String> - The kind of resource to which + # the tag is applied. Currently, Auto Scaling supports the + # auto-scaling-group resource type. + # * 'Value'<~String> - The value of the tag. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeTags.html + # + def describe_tags(options={}) + if filters = options.delete('Filters') + options.merge!(Fog::AWS.indexed_filters(filters)) + end + request({ + 'Action' => 'DescribeTags', + :parser => Fog::Parsers::AWS::AutoScaling::DescribeTags.new + }.merge!(options)) + end + end + + class Mock + def describe_tags(options={}) + raise Fog::Mock::NotImplementedError + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/describe_termination_policy_types.rb b/lib/fog/aws/requests/auto_scaling/describe_termination_policy_types.rb new file mode 100644 index 000000000..96e39c00d --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/describe_termination_policy_types.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/describe_termination_policy_types' + + # Returns a list of all termination policies supported by Auto Scaling. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeTerminationPolicyTypesResult'<~Hash>: + # * 'TerminationPolicyTypes'<~Array>: + # * terminationtype<~String>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DescribeTerminationPolicyTypes.html + # + def describe_termination_policy_types() + request({ + 'Action' => 'DescribeTerminationPolicyTypes', + :idempotent => true, + :parser => Fog::Parsers::AWS::AutoScaling::DescribeTerminationPolicyTypes.new + }) + end + end + + class Mock + def describe_termination_policy_types() + results = { 'TerminationPolicyTypes' => [] } + self.data[:termination_policy_types].each do |termination_policy_type| + results['TerminationPolicyTypes'] << termination_policy_type + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeTerminationPolicyTypesResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/disable_metrics_collection.rb b/lib/fog/aws/requests/auto_scaling/disable_metrics_collection.rb new file mode 100644 index 000000000..13bb61b86 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/disable_metrics_collection.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Disables monitoring of group metrics for the Auto Scaling group + # specified in AutoScalingGroupName. You can specify the list of + # affected metrics with the Metrics parameter. + # + # ==== Parameters + # * 'AutoScalingGroupName'<~String> - The name or ARN of the Auto + # Scaling group. + # * options<~Hash>: + # * Metrics<~Array> - The list of metrics to disable. If no metrics + # are specified, all metrics are disabled. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_DisableMetricsCollection.html + # + def disable_metrics_collection(auto_scaling_group_name, options = {}) + if metrics = options.delete('Metrics') + options.merge!(Aws.indexed_param('Metrics.member.%d', [*metrics])) + end + request({ + 'Action' => 'DisableMetricsCollection', + 'AutoScalingGroupName' => auto_scaling_group_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def disable_metrics_collection(auto_scaling_group_name, options = {}) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + Fog::AWS::AutoScaling::ValidationError.new("Group #{auto_scaling_group_name} not found") + end + + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/enable_metrics_collection.rb b/lib/fog/aws/requests/auto_scaling/enable_metrics_collection.rb new file mode 100644 index 000000000..84fc35329 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/enable_metrics_collection.rb @@ -0,0 +1,60 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Enables monitoring of group metrics for the Auto Scaling group + # specified in auto_scaling_group_name. You can specify the list of + # enabled metrics with the metrics parameter. + # + # Auto scaling metrics collection can be turned on only if the + # instance_monitoring.enabled flag, in the Auto Scaling group's launch + # configuration, is set to true. + # + # ==== Parameters + # * 'AutoScalingGroupName'<~String>: The name or ARN of the Auto + # Scaling group + # * options<~Hash>: + # * Granularity<~String>: The granularity to associate with the + # metrics to collect. + # * Metrics<~Array>: The list of metrics to collect. If no metrics + # are specified, all metrics are enabled. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_EnableMetricsCollection.html + # + def enable_metrics_collection(auto_scaling_group_name, granularity, options = {}) + if metrics = options.delete('Metrics') + options.merge!(Aws.indexed_param('Metrics.member.%d', [*metrics])) + end + request({ + 'Action' => 'EnableMetricsCollection', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'Granularity' => granularity, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def enable_metrics_collection(auto_scaling_group_name, granularity, options = {}) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + Fog::AWS::AutoScaling::ValidationError.new("Group #{auto_scaling_group_name} not found") + end + unless self.data[:metric_collection_types][:granularities].include?(granularity) + Fog::AWS::AutoScaling::ValidationError.new('Valid metrics granularity type is: [1Minute].') + end + + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/execute_policy.rb b/lib/fog/aws/requests/auto_scaling/execute_policy.rb new file mode 100644 index 000000000..e6cd51996 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/execute_policy.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Runs the policy you create for your Auto Scaling group in + # put_scaling_policy. + # + # ==== Parameters + # * 'PolicyName'<~String> - The name or PolicyARN of the policy you + # want to run. + # * options<~Hash>: + # * 'AutoScalingGroupName'<~String> - The name or ARN of the Auto + # Scaling group. + # * 'HonorCooldown'<~Boolean> - Set to true if you want Auto Scaling + # to reject this request if the Auto Scaling group is in cooldown. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_ExecutePolicy.html + # + def execute_policy(policy_name, options = {}) + request({ + 'Action' => 'ExecutePolicy', + 'PolicyName' => policy_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def execute_policy(policy_name, options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/put_notification_configuration.rb b/lib/fog/aws/requests/auto_scaling/put_notification_configuration.rb new file mode 100644 index 000000000..31f4eb304 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/put_notification_configuration.rb @@ -0,0 +1,64 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/put_notification_configuration' + + # Creates a notification configuration for an Auto Scaling group. To + # update an existing policy, overwrite the existing notification + # configuration name and set the parameter(s) you want to change. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * notification_types<~Array> - The type of events that will trigger + # the notification. + # * topic_arn<~String> - The Amazon Resource Name (ARN) of the Amazon + # Simple Notification Service (SNS) topic. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_PutNotificationConfiguration.html + # + def put_notification_configuration(auto_scaling_group_name, notification_types, topic_arn) + params = Aws.indexed_param('NotificationTypes.member.%d', [*notification_types]) + request({ + 'Action' => 'PutNotificationConfiguration', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'TopicARN' => topic_arn, + :parser => Fog::Parsers::AWS::AutoScaling::PutNotificationConfiguration.new + }.merge!(params)) + end + end + + class Mock + def put_notification_configuration(auto_scaling_group_name, notification_types, topic_arn) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError.new("AutoScalingGroup name not found - #{auto_scaling_group_name}") + end + if notification_types.to_a.empty? + raise Fog::AWS::AutoScaling::ValidationError.new("1 validation error detected: Value null at 'notificationTypes' failed to satisfy constraint: Member must not be null") + end + invalid_types = notification_types.to_a - self.data[:notification_types] + unless invalid_types.empty? + raise Fog::AWS::AutoScaling::ValidationError.new(""#{invalid_types.first}" is not a valid Notification Type.") + end + + self.data[:notification_configurations][auto_scaling_group_name] ||= {} + self.data[:notification_configurations][auto_scaling_group_name][topic_arn] = notification_types.to_a.uniq + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/put_scaling_policy.rb b/lib/fog/aws/requests/auto_scaling/put_scaling_policy.rb new file mode 100644 index 000000000..f73c1b459 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/put_scaling_policy.rb @@ -0,0 +1,79 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/put_scaling_policy' + + # Creates or updates a policy for an Auto Scaling group. To update an + # existing policy, use the existing policy name and set the + # parameter(s) you want to change. Any existing parameter not changed + # in an update to an existing policy is not changed in this update + # request. + # + # ==== Parameters + # * adjustment_type<~String> - Specifies whether the scaling_adjustment + # is an absolute number or a percentage of the current capacity. + # * auto_scaling_group_name<~String> - The name or ARN of the Auto + # Scaling group. + # * policy_name<~String> - The name of the policy you want to create or + # update. + # * scaling_adjustment<~Integer> - The number of instances by which to + # scale. AdjustmentType determines the interpretation of this number + # (e.g., as an absolute number or as a percentage of the existing + # Auto Scaling group size). A positive increment adds to the current + # capacity and a negative value removes from the current capacity. + # * options<~Hash>: + # * 'CoolDown'<~Integer> - The amount of time, in seconds, after a + # scaling activity completes before any further trigger-related + # scaling activities can start + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'PutScalingPolicyResult'<~Hash>: + # * 'PolicyARN'<~String> - A policy's Amazon Resource Name (ARN). + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_PutScalingPolicy.html + # + def put_scaling_policy(adjustment_type, auto_scaling_group_name, policy_name, scaling_adjustment, options = {}) + request({ + 'Action' => 'PutScalingPolicy', + 'AdjustmentType' => adjustment_type, + 'AutoScalingGroupName' => auto_scaling_group_name, + 'PolicyName' => policy_name, + 'ScalingAdjustment' => scaling_adjustment, + :parser => Fog::Parsers::AWS::AutoScaling::PutScalingPolicy.new + }.merge!(options)) + end + end + + class Mock + def put_scaling_policy(adjustment_type, auto_scaling_group_name, policy_name, scaling_adjustment, options = {}) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError.new('Auto Scaling Group name not found - null') + end + self.data[:scaling_policies][policy_name] = { + 'AdjustmentType' => adjustment_type, + 'Alarms' => [], + 'AutoScalingGroupName' => auto_scaling_group_name, + 'Cooldown' => 0, + 'MinAdjustmentStep' => 0, + 'PolicyARN' => Fog::AWS::Mock.arn('autoscaling', self.data[:owner_id], "scalingPolicy:00000000-0000-0000-0000-000000000000:autoScalingGroupName/#{auto_scaling_group_name}:policyName/#{policy_name}", self.region), + 'PolicyName' => policy_name, + 'ScalingAdjustment' => scaling_adjustment + }.merge!(options) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/put_scheduled_update_group_action.rb b/lib/fog/aws/requests/auto_scaling/put_scheduled_update_group_action.rb new file mode 100644 index 000000000..b9be811fb --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/put_scheduled_update_group_action.rb @@ -0,0 +1,64 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Creates a scheduled scaling action for a Auto Scaling group. If you + # leave a parameter unspecified, the corresponding value remains + # unchanged in the affected Auto Scaling group. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name or ARN of the Auto + # Scaling Group. + # * scheduled_action_name<~String> - Name of this scaling action. + # * time<~Datetime> - The time for this action to start (deprecated: + # use StartTime, EndTime and Recurrence). + # * options<~Hash>: + # * 'DesiredCapacity'<~Integer> - The number of EC2 instances that + # should be running in this group. + # * 'EndTime'<~DateTime> - The time for this action to end. + # * 'MaxSize'<~Integer> - The maximum size for the Auto Scaling + # group. + # * 'MinSize'<~Integer> - The minimum size for the Auto Scaling + # group. + # * 'Recurrence'<~String> - The time when recurring future actions + # will start. Start time is specified by the user following the + # Unix cron syntax format. When StartTime and EndTime are specified + # with Recurrence, they form the boundaries of when the recurring + # action will start and stop. + # * 'StartTime'<~DateTime> - The time for this action to start + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_PutScheduledUpdateGroupAction.html + # + def put_scheduled_update_group_action(auto_scaling_group_name, scheduled_action_name, time=nil, options = {}) + # The 'Time' paramenter is now an alias for StartTime and needs to be identical if specified. + time = options['StartTime'].nil? ? time : options['StartTime'] + if !time.nil? + time = time.class == Time ? time.utc.iso8601 : Time.parse(time).utc.iso8601 + end + request({ + 'Action' => 'PutScheduledUpdateGroupAction', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'ScheduledActionName' => scheduled_action_name, + 'Time' => time, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def put_scheduled_update_group_action(auto_scaling_group_name, scheduled_policy_name, time, options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/resume_processes.rb b/lib/fog/aws/requests/auto_scaling/resume_processes.rb new file mode 100644 index 000000000..4df6a4715 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/resume_processes.rb @@ -0,0 +1,53 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Resumes Auto Scaling processes for an Auto Scaling group. + # + # ==== Parameters + # * auto_scaling_group_name'<~String> - The name or Amazon Resource + # Name (ARN) of the Auto Scaling group. + # * options<~Hash>: + # * 'ScalingProcesses'<~Array> - The processes that you want to + # resume. To resume all process types, omit this parameter. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_ResumeProcesses.html + # + def resume_processes(auto_scaling_group_name, options = {}) + if scaling_processes = options.delete('ScalingProcesses') + options.merge!(Aws.indexed_param('ScalingProcesses.member.%d', [*scaling_processes])) + end + request({ + 'Action' => 'ResumeProcesses', + 'AutoScalingGroupName' => auto_scaling_group_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def resume_processes(auto_scaling_group_name, options = {}) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError.new("AutoScalingGroup name not found - no such group: #{auto_scaling_group_name}") + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/set_desired_capacity.rb b/lib/fog/aws/requests/auto_scaling/set_desired_capacity.rb new file mode 100644 index 000000000..b7c11be89 --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/set_desired_capacity.rb @@ -0,0 +1,81 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Adjusts the desired size of the AutoScalingGroup by initiating + # scaling activities. When reducing the size of the group, it is not + # possible to define which EC2 instances will be terminated. This + # applies to any auto-scaling decisions that might result in + # terminating instances. + # + # There are two common use cases for set_desired_capacity: one for + # users of the Auto Scaling triggering system, and another for + # developers who write their own triggering systems. Both use cases + # relate to the concept of cooldown. + # + # In the first case, if you use the Auto Scaling triggering system, + # set_desired_capacity changes the size of your Auto Scaling group + # without regard to the cooldown period. This could be useful, for + # example, if Auto Scaling did something unexpected for some reason. If + # your cooldown period is 10 minutes, Auto Scaling would normally + # reject requests to change the size of the group for that entire 10 + # minute period. The set_desired_capacity command allows you to + # circumvent this restriction and change the size of the group before + # the end of the cooldown period. + # + # In the second case, if you write your own triggering system, you can + # use set_desired_capacity to control the size of your Auto Scaling + # group. If you want the same cooldown functionality that Auto Scaling + # offers, you can configure set_desired_capacity to honor cooldown by + # setting the HonorCooldown parameter to true. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * desired_capacity<~Integer> - The new capacity setting for the Auto + # Scaling group. + # * options<~Hash>: + # * 'HonorCooldown'<~Boolean> - By default, set_desired_capacity + # overrides any cooldown period. Set to true if you want Auto + # Scaling to reject this request if the Auto Scaling group is in + # cooldown. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_SetDesiredCapacity.html + # + def set_desired_capacity(auto_scaling_group_name, desired_capacity, options = {}) + request({ + 'Action' => 'SetDesiredCapacity', + 'AutoScalingGroupName' => auto_scaling_group_name, + 'DesiredCapacity' => desired_capacity, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def set_desired_capacity(auto_scaling_group_name, desired_capacity, options = {}) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + Fog::AWS::AutoScaling::ValidationError.new('AutoScalingGroup name not found - null') + end + self.data[:auto_scaling_groups][auto_scaling_group_name]['DesiredCapacity'] = desired_capacity + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/set_instance_health.rb b/lib/fog/aws/requests/auto_scaling/set_instance_health.rb new file mode 100644 index 000000000..775806e7b --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/set_instance_health.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Sets the health status of an instance. + # + # ==== Parameters + # * health_status<~String> - The health status of the instance. + # "Healthy" means that the instance is healthy and should remain in + # service. "Unhealthy" means that the instance is unhealthy. Auto + # Scaling should terminate and replace it. + # * instance_id<~String> - The identifier of the EC2 instance. + # * options<~Hash>: + # * 'ShouldRespectGracePeriod'<~Boolean> - If true, this call should + # respect the grace period associated with the group. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_SetInstanceHealth.html + # + def set_instance_health(health_status, instance_id, options = {}) + request({ + 'Action' => 'SetInstanceHealth', + 'HealthStatus' => health_status, + 'InstanceId' => instance_id, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def set_instance_health(health_status, instance_id, options = {}) + unless self.data[:health_states].include?(health_status) + raise Fog::AWS::AutoScaling::ValidationError.new('Valid instance health states are: [#{self.data[:health_states].join(", ")}].') + end + + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/suspend_processes.rb b/lib/fog/aws/requests/auto_scaling/suspend_processes.rb new file mode 100644 index 000000000..78424fd8d --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/suspend_processes.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Suspends Auto Scaling processes for an Auto Scaling group. To suspend + # specific process types, specify them by name with the + # ScalingProcesses parameter. To suspend all process types, omit the + # ScalingProcesses.member.N parameter. + # + # ==== Parameters + # * 'AutoScalingGroupName'<~String> - The name or Amazon Resource Name + # (ARN) of the Auto Scaling group. + # * options<~Hash>: + # * 'ScalingProcesses'<~Array> - The processes that you want to + # suspend. To suspend all process types, omit this parameter. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_SuspendProcesses.html + # + def suspend_processes(auto_scaling_group_name, options = {}) + if scaling_processes = options.delete('ScalingProcesses') + options.merge!(Aws.indexed_param('ScalingProcesses.member.%d', [*scaling_processes])) + end + request({ + 'Action' => 'SuspendProcesses', + 'AutoScalingGroupName' => auto_scaling_group_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def suspend_processes(auto_scaling_group_name, options = {}) + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError.new("AutoScalingGroup name not found - no such group: #{auto_scaling_group_name}") + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/terminate_instance_in_auto_scaling_group.rb b/lib/fog/aws/requests/auto_scaling/terminate_instance_in_auto_scaling_group.rb new file mode 100644 index 000000000..4242543cb --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/terminate_instance_in_auto_scaling_group.rb @@ -0,0 +1,59 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/terminate_instance_in_auto_scaling_group' + + # Terminates the specified instance. Optionally, the desired group size + # can be adjusted. + # + # ==== Parameters + # * instance_id<~String> - The ID of the EC2 instance to be terminated. + # * should_decrement_desired_capacity<~Boolean> - Specifies whether + # (true) or not (false) terminating this instance should also + # decrement the size of the AutoScalingGroup. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'TerminateGroupInAutoScalingInstanceResult'<~Hash>: + # * 'ActivityId'<~String> - Specifies the ID of the activity. + # * 'AutoScalingGroupName'<~String> - The name of the Auto + # Scaling group. + # * 'Cause'<~String> - Contains the reason the activity was + # begun. + # * 'Description'<~String> - Contains a friendly, more verbose + # description of the scaling activity. + # * 'EndTime'<~Time> - Provides the end time of this activity. + # * 'Progress'<~Integer> - Specifies a value between 0 and 100 + # that indicates the progress of the activity. + # * 'StartTime'<~Time> - Provides the start time of this + # activity. + # * 'StatusCode'<~String> - Contains the current status of the + # activity. + # * 'StatusMessage'<~String> - Contains a friendly, more verbose + # description of the activity status. + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_TerminateInstanceInAutoScalingGroup.html + # + def terminate_instance_in_auto_scaling_group(instance_id, should_decrement_desired_capacity) + request({ + 'Action' => 'TerminateInstanceInAutoScalingGroup', + 'InstanceId' => instance_id, + 'ShouldDecrementDesiredCapacity' => should_decrement_desired_capacity.to_s, + :parser => Fog::Parsers::AWS::AutoScaling::TerminateInstanceInAutoScalingGroup.new + }) + end + end + + class Mock + def terminate_instance_in_auto_scaling_group(instance_id, should_decrement_desired_capacity) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/auto_scaling/update_auto_scaling_group.rb b/lib/fog/aws/requests/auto_scaling/update_auto_scaling_group.rb new file mode 100644 index 000000000..48eee8c4f --- /dev/null +++ b/lib/fog/aws/requests/auto_scaling/update_auto_scaling_group.rb @@ -0,0 +1,93 @@ +module Fog + module AWS + class AutoScaling + class Real + require 'fog/aws/parsers/auto_scaling/basic' + + # Updates the configuration for the specified AutoScalingGroup. + # + # The new settings are registered upon the completion of this call. Any + # launch configuration settings take effect on any triggers after this + # call returns. Triggers that are currently in progress aren't + # affected. + # + # ==== Parameters + # * auto_scaling_group_name<~String> - The name of the Auto Scaling + # group. + # * options<~Hash>: + # * 'AvailabilityZones'<~Array> - Availability zones for the group. + # * 'DefaultCooldown'<~Integer> - The amount of time, in seconds, + # after a scaling activity completes before any further trigger- + # related scaling activities can start + # * 'DesiredCapacity'<~Integer> - The desired capacity for the Auto + # Scaling group. + # * 'HealthCheckGracePeriod'<~Integer> - The length of time that Auto + # Scaling waits before checking an instance's health status.The + # grace period begins when an instance comes into service. + # * 'HealthCheckType'<~String> - The service of interest for the + # health status check, either "EC2" for Amazon EC2 or "ELB" for + # Elastic Load Balancing. + # * 'LaunchConfigurationName'<~String> - The name of the launch + # configuration. + # * 'MaxSize'<~Integer> - The maximum size of the Auto Scaling group. + # * 'MinSize'<~Integer> - The minimum size of the Auto Scaling group. + # * 'PlacementGroup'<~String> - The name of the cluster placement + # group, if applicable. + # * 'TerminationPolicies'<~Array> - A standalone termination policy + # or a list of termination policies used to select the instance to + # terminate. The policies are executed in the order that they are + # listed. + # * 'VPCZoneIdentifier'<~String> - The subnet identifier for the + # Amazon VPC connection, if applicable. You can specify several + # subnets in a comma-separated list. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # + # ==== See Also + # http://docs.amazonwebservices.com/AutoScaling/latest/APIReference/API_UpdateAutoScalingGroup.html + # + + ExpectedOptions[:update_auto_scaling_group] = %w[AvailabilityZones DefaultCooldown DesiredCapacity HealthCheckGracePeriod HealthCheckType LaunchConfigurationName MaxSize MinSize PlacementGroup TerminationPolicies VPCZoneIdentifier] + + def update_auto_scaling_group(auto_scaling_group_name, options = {}) + if availability_zones = options.delete('AvailabilityZones') + options.merge!(Aws.indexed_param('AvailabilityZones.member.%d', [*availability_zones])) + end + if termination_policies = options.delete('TerminationPolicies') + options.merge!(Aws.indexed_param('TerminationPolicies.member.%d', [*termination_policies])) + end + request({ + 'Action' => 'UpdateAutoScalingGroup', + 'AutoScalingGroupName' => auto_scaling_group_name, + :parser => Fog::Parsers::AWS::AutoScaling::Basic.new + }.merge!(options)) + end + end + + class Mock + def update_auto_scaling_group(auto_scaling_group_name, options = {}) + unexpected_options = options.keys - ExpectedOptions[:update_auto_scaling_group] + unless unexpected_options.empty? + raise Fog::AWS::AutoScaling::ValidationError.new("Options #{unexpected_options.join(',')} should not be included in request") + end + + unless self.data[:auto_scaling_groups].key?(auto_scaling_group_name) + raise Fog::AWS::AutoScaling::ValidationError.new('AutoScalingGroup name not found - null') + end + self.data[:auto_scaling_groups][auto_scaling_group_name].merge!(options) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/check_dns_availability.rb b/lib/fog/aws/requests/beanstalk/check_dns_availability.rb new file mode 100644 index 000000000..afebeb5a0 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/check_dns_availability.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/check_dns_availability' + + # Checks if the specified CNAME is available. + # + # ==== Options + # * CNAMEPrefix<~String>: The prefix used when this CNAME is reserved + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CheckDNSAvailability.html + # + def check_dns_availability(options) + request({ + 'Operation' => 'CheckDNSAvailability', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::CheckDNSAvailability.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/create_application.rb b/lib/fog/aws/requests/beanstalk/create_application.rb new file mode 100644 index 000000000..7e1ee4b6a --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/create_application.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/create_application' + + # Creates an application that has one configuration template named default and no application versions. + # + # ==== Options + # * ApplicationName<~String>: The name of the application. + # * Description<~String>: Describes the application. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateApplication.html + # + def create_application(options={}) + request({ + 'Operation' => 'CreateApplication', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::CreateApplication.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/create_application_version.rb b/lib/fog/aws/requests/beanstalk/create_application_version.rb new file mode 100644 index 000000000..d4a48a3f7 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/create_application_version.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/create_application_version' + + # Creates an application version for the specified application. + # + # ==== Options + # * ApplicationName<~String>: The name of the application. If no application is found with this name, + # and AutoCreateApplication is false, returns an InvalidParameterValue error. + # * AutoCreateApplication<~Boolean>: If true, create the application if it doesn't exist. + # * Description<~String>: Describes this version. + # * SourceBundle<~Hash>: The Amazon S3 bucket and key that identify the location of the source bundle + # for this version. Use keys 'S3Bucket' and 'S3Key' to describe location. + # * VersionLabel<~String>: A label identifying this version. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateApplicationVersion.html + # + def create_application_version(options={}) + if source_bundle = options.delete('SourceBundle') + # flatten hash + options.merge!({ + 'SourceBundle.S3Bucket' => source_bundle['S3Bucket'], + 'SourceBundle.S3Key' => source_bundle['S3Key'] + }) + end + request({ + 'Operation' => 'CreateApplicationVersion', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::CreateApplicationVersion.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/create_configuration_template.rb b/lib/fog/aws/requests/beanstalk/create_configuration_template.rb new file mode 100644 index 000000000..18c103991 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/create_configuration_template.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/create_configuration_template' + + # Creates a configuration template. Templates are associated with a specific application and are used to + # deploy different versions of the application with the same configuration settings. + # + # ==== Options + # * ApplicationName<~String>: The name of the application to associate with this configuration template. + # If no application is found with this name, Aws Elastic Beanstalk returns an InvalidParameterValue error. + # * Description<~String>: Describes this configuration. + # * EnvironmentId<~String>: The ID of the environment used with this configuration template. + # * OptionSettings<~Hash>: If specified, Aws Elastic Beanstalk sets the specified configuration option + # to the requested value. The new value overrides the value obtained from the solution stack or the + # source configuration template. + # * SolutionStackName<~String>: The name of the solution stack used by this configuration. The solution + # stack specifies the operating system, architecture, and application server for a configuration template. + # It determines the set of configuration options as well as the possible and default values. + # * SourceConfiguration<~String>: If specified, Aws Elastic Beanstalk uses the configuration values from the + # specified configuration template to create a new configuration. + # * TemplateName<~String>: The name of the configuration template. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateConfigurationTemplate.html + # + def create_configuration_template(options={}) + if option_settings = options.delete('OptionSettings') + options.merge!(Aws.indexed_param('OptionSettings.member.%d', [*option_settings])) + end + if option_settings = options.delete('SourceConfiguration') + options.merge!(Aws.serialize_keys('SourceConfiguration', option_settings)) + end + request({ + 'Operation' => 'CreateConfigurationTemplate', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::CreateConfigurationTemplate.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/create_environment.rb b/lib/fog/aws/requests/beanstalk/create_environment.rb new file mode 100644 index 000000000..0a77b5b69 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/create_environment.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/create_environment' + + # Launches an environment for the specified application using the specified configuration. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to include only those that are associated with this application. + # * CNAMEPrefix<~String>: If specified, the environment attempts to use this value as the prefix for the CNAME. + # If not specified, the environment uses the environment name. + # * Description<~String>: Describes this environment. + # * EnvironmentName<~String>: A unique name for the deployment environment. Used in the application URL. + # * OptionSettings<~Array>: If specified, Aws Elastic Beanstalk sets the specified configuration options to + # the requested value in the configuration set for the new environment. These override the values obtained + # from the solution stack or the configuration template. + # * OptionsToRemove<~Array>: A list of custom user-defined configuration options to remove from the + # configuration set for this new environment. + # * SolutionStackName<~String>: This is an alternative to specifying a configuration name. If specified, + # Aws Elastic Beanstalk sets the configuration values to the default values associated with the + # specified solution stack. + # * TemplateName<~String>: The name of the configuration template to use in deployment. If no configuration + # template is found with this name, Aws Elastic Beanstalk returns an InvalidParameterValue error. + # * VersionLabel<~String>: The name of the application version to deploy. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateEnvironment.html + # + def create_environment(options={}) + if option_settings = options.delete('OptionSettings') + options.merge!(Aws.indexed_param('OptionSettings.member.%d', [*option_settings])) + end + if options_to_remove = options.delete('OptionsToRemove') + options.merge!(Aws.indexed_param('OptionsToRemove.member.%d', [*options_to_remove])) + end + request({ + 'Operation' => 'CreateEnvironment', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::CreateEnvironment.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/create_storage_location.rb b/lib/fog/aws/requests/beanstalk/create_storage_location.rb new file mode 100644 index 000000000..6b67e0af5 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/create_storage_location.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/create_storage_location' + + # Creates the Amazon S3 storage location for the account. + # + # ==== Options + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateStorageLocation.html + # + def create_storage_location() + request({ + 'Operation' => 'CreateStorageLocation', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::CreateStorageLocation.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/delete_application.rb b/lib/fog/aws/requests/beanstalk/delete_application.rb new file mode 100644 index 000000000..b0b451057 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/delete_application.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Deletes the specified application along with all associated versions and configurations. + # + # ==== Options + # * application_name<~String>: The name of the application to delete. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DeleteApplication.html + # + def delete_application(application_name) + options = { 'ApplicationName' => application_name } + request({ + 'Operation' => 'DeleteApplication', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/delete_application_version.rb b/lib/fog/aws/requests/beanstalk/delete_application_version.rb new file mode 100644 index 000000000..7e48a6416 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/delete_application_version.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Deletes the specified version from the specified application. + # + # ==== Options + # * application_name<~String>: The name of the application to delete releases from. + # * version_label<~String>: The label of the version to delete. + # * delete_source_bundle<~Boolean>: Indicates whether to delete the associated source bundle from Amazon S3. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DeleteApplication.html + # + def delete_application_version(application_name, version_label, delete_source_bundle = nil) + options = { + 'ApplicationName' => application_name, + 'VersionLabel' => version_label + } + options['DeleteSourceBundle'] = delete_source_bundle unless delete_source_bundle.nil? + + request({ + 'Operation' => 'DeleteApplicationVersion', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/delete_configuration_template.rb b/lib/fog/aws/requests/beanstalk/delete_configuration_template.rb new file mode 100644 index 000000000..010215853 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/delete_configuration_template.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Deletes the specified configuration template. + # + # ==== Options + # * application_name<~String>: The name of the application to delete the configuration template from. + # * template_name<~String>: The name of the configuration template to delete. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DeleteConfigurationTemplate.html + # + def delete_configuration_template(application_name, template_name) + options = { + 'ApplicationName' => application_name, + 'TemplateName' => template_name + } + + request({ + 'Operation' => 'DeleteConfigurationTemplate', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/delete_environment_configuration.rb b/lib/fog/aws/requests/beanstalk/delete_environment_configuration.rb new file mode 100644 index 000000000..bcaee5ee5 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/delete_environment_configuration.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Deletes the draft configuration associated with the running environment. + # + # ==== Options + # * application_name<~String>: The name of the application the environment is associated with. + # * environment_name<~String>: The name of the environment to delete the draft configuration from. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DeleteConfigurationTemplate.html + # + def delete_environment_configuration(application_name, environment_name) + options = { + 'ApplicationName' => application_name, + 'EnvironmentName' => environment_name + } + + request({ + 'Operation' => 'DeleteEnvironmentConfiguration', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_application_versions.rb b/lib/fog/aws/requests/beanstalk/describe_application_versions.rb new file mode 100644 index 000000000..7eda21282 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_application_versions.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_application_versions' + + # Returns descriptions for existing application versions. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions to + # only include ones that are associated with the specified application. + # * VersionLabels<~Array>: If specified, restricts the returned descriptions to only include ones that have + # the specified version labels. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeApplicationVersions.html + # + def describe_application_versions(options={}) + if version_labels = options.delete('VersionLabels') + options.merge!(Aws.indexed_param('VersionLabels.member.%d', [*version_labels])) + end + request({ + 'Operation' => 'DescribeApplicationVersions', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeApplicationVersions.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_applications.rb b/lib/fog/aws/requests/beanstalk/describe_applications.rb new file mode 100644 index 000000000..4079557cd --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_applications.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_applications' + + # Returns the descriptions of existing applications. + # + # ==== Options + # * application_names<~Array>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to only include those with the specified names. + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeApplications.html + # + def describe_applications(application_names=[]) + options = {} + options.merge!(Aws.indexed_param('ApplicationNames.member.%d', [*application_names])) + request({ + 'Operation' => 'DescribeApplications', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeApplications.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_configuration_options.rb b/lib/fog/aws/requests/beanstalk/describe_configuration_options.rb new file mode 100644 index 000000000..61b4baabc --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_configuration_options.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_configuration_options' + + # Describes the configuration options that are used in a particular configuration template or environment, + # or that a specified solution stack defines. The description includes the values the options, + # their default values, and an indication of the required action on a running environment + # if an option value is changed. + # + # ==== Options + # * ApplicationName<~String>: The name of the application associated with the configuration template or + # environment. Only needed if you want to describe the configuration options associated with either the + # configuration template or environment. + # * EnvironmentName<~String>: The name of the environment whose configuration options you want to describe. + # * Options<~Array>: If specified, restricts the descriptions to only the specified options. + # * SolutionStackName<~String>: The name of the solution stack whose configuration options you want to describe. + # * TemplateName<~String>: The name of the configuration template whose configuration options you want to describe. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeConfigurationOptions.html + # + def describe_configuration_options(options={}) + if option_filters = options.delete('Options') + options.merge!(Aws.indexed_param('Options.member.%d', [*option_filters])) + end + request({ + 'Operation' => 'DescribeConfigurationOptions', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeConfigurationOptions.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_configuration_settings.rb b/lib/fog/aws/requests/beanstalk/describe_configuration_settings.rb new file mode 100644 index 000000000..6c3e2619f --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_configuration_settings.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_configuration_settings' + + # Returns a description of the settings for the specified configuration set, that is, either a configuration + # template or the configuration set associated with a running environment. + # + # ==== Options + # * ApplicationName<~String>: The application for the environment or configuration template. + # * EnvironmentName<~String>: The name of the environment to describe. + # * TemplateName<~String>: The name of the configuration template to describe. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeConfigurationSettings.html + # + def describe_configuration_settings(options={}) + request({ + 'Operation' => 'DescribeConfigurationSettings', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeConfigurationSettings.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_environment_resources.rb b/lib/fog/aws/requests/beanstalk/describe_environment_resources.rb new file mode 100644 index 000000000..b64797bd9 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_environment_resources.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_environment_resources' + + # Returns Aws resources for this environment. + # + # ==== Options + # * EnvironmentId + # * EnvironmentName + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeEnvironmentResources.html + # + def describe_environment_resources(options={}) + request({ + 'Operation' => 'DescribeEnvironmentResources', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeEnvironmentResources.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_environments.rb b/lib/fog/aws/requests/beanstalk/describe_environments.rb new file mode 100644 index 000000000..d83bb6b16 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_environments.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_environments' + + # Returns descriptions for existing environments. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to include only those that are associated with this application. + # * EnvironmentIds + # * EnvironmentNames + # * IncludeDeleted + # * IncludedDeletedBackTo + # * VersionLabel<~String>: + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeEnvironments.html + # + def describe_environments(options={}) + if environment_ids = options.delete('EnvironmentIds') + options.merge!(Aws.indexed_param('EnvironmentIds.member.%d', [*environment_ids])) + end + if environment_names = options.delete('EnvironmentNames') + options.merge!(Aws.indexed_param('EnvironmentNames.member.%d', [*environment_names])) + end + request({ + 'Operation' => 'DescribeEnvironments', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeEnvironments.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/describe_events.rb b/lib/fog/aws/requests/beanstalk/describe_events.rb new file mode 100644 index 000000000..3a3efeef2 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/describe_events.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/describe_events' + + # Returns list of event descriptions matching criteria up to the last 6 weeks. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to include only those that are associated with this application. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_DescribeEnvironments.html + # + def describe_events(options={}) + request({ + 'Operation' => 'DescribeEvents', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::DescribeEvents.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/list_available_solution_stacks.rb b/lib/fog/aws/requests/beanstalk/list_available_solution_stacks.rb new file mode 100644 index 000000000..d478af639 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/list_available_solution_stacks.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/list_available_solution_stacks' + + # Checks if the specified CNAME is available. + # + # ==== Options + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CheckDNSAvailability.html + # + def list_available_solution_stacks() + request({ + 'Operation' => 'ListAvailableSolutionStacks', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::ListAvailableSolutionStacks.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/rebuild_environment.rb b/lib/fog/aws/requests/beanstalk/rebuild_environment.rb new file mode 100644 index 000000000..8a2d4783c --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/rebuild_environment.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Deletes and recreates all of the Aws resources (for example: the Auto Scaling group, load balancer, etc.) + # for a specified environment and forces a restart. + # + # ==== Options + # * EnvironmentId + # * EnvironmentName + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_RebuildEnvironment.html + # + def rebuild_environment(options={}) + request({ + 'Operation' => 'RebuildEnvironment', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/request_environment_info.rb b/lib/fog/aws/requests/beanstalk/request_environment_info.rb new file mode 100644 index 000000000..0385fd30f --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/request_environment_info.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Returns Aws resources for this environment. + # + # ==== Options + # * EnvironmentId + # * EnvironmentName + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_RequestEnvironmentInfo.html + # + def request_environment_info(options={}) + request({ + 'Operation' => 'RequestEnvironmentInfo', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/restart_app_server.rb b/lib/fog/aws/requests/beanstalk/restart_app_server.rb new file mode 100644 index 000000000..401cfed39 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/restart_app_server.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Returns Aws resources for this environment. + # + # ==== Options + # * EnvironmentId + # * EnvironmentName + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_RestartAppServer.html + # + def restart_app_server(options={}) + request({ + 'Operation' => 'RestartAppServer', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/retrieve_environment_info.rb b/lib/fog/aws/requests/beanstalk/retrieve_environment_info.rb new file mode 100644 index 000000000..9165c9f5d --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/retrieve_environment_info.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/retrieve_environment_info' + + # Returns Aws resources for this environment. + # + # ==== Options + # * EnvironmentId + # * EnvironmentName + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_RetrieveEnvironmentInfo.html + # + def retrieve_environment_info(options={}) + request({ + 'Operation' => 'RetrieveEnvironmentInfo', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::RetrieveEnvironmentInfo.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/swap_environment_cnames.rb b/lib/fog/aws/requests/beanstalk/swap_environment_cnames.rb new file mode 100644 index 000000000..aad9f4224 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/swap_environment_cnames.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/empty' + + # Swaps the CNAMEs of two environments. + # + # ==== Options + # * EnvironmentId + # * EnvironmentName + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_SwapEnvironmentCNAMEs.html + # + def swap_environment_cnames(options={}) + request({ + 'Operation' => 'SwapEnvironmentCNAMEs', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::Empty.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/terminate_environment.rb b/lib/fog/aws/requests/beanstalk/terminate_environment.rb new file mode 100644 index 000000000..b7e01baf4 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/terminate_environment.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/terminate_environment' + + # Terminates the specified environment. + # + # ==== Options + # * EnvironmentId<~String>: The ID of the environment to terminate. + # * EnvironmentName<~String>: The name of the environment to terminate. + # * TerminateResources<~Boolean>: Indicates whether the associated Aws resources should shut down when the + # environment is terminated + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_TerminateEnvironment.html + # + def terminate_environment(options={}) + request({ + 'Operation' => 'TerminateEnvironment', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::TerminateEnvironment.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/update_application.rb b/lib/fog/aws/requests/beanstalk/update_application.rb new file mode 100644 index 000000000..c8055c3c7 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/update_application.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/update_application' + + # Updates the specified application to have the specified properties. + # + # ==== Options + # * ApplicationName<~String>: The name of the application to update. If no such application is found, + # UpdateApplication returns an InvalidParameterValue error. + # * Description<~String>: A new description for the application. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_UpdateApplication.html + # + def update_application(options) + request({ + 'Operation' => 'UpdateApplication', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::UpdateApplication.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/update_application_version.rb b/lib/fog/aws/requests/beanstalk/update_application_version.rb new file mode 100644 index 000000000..ef1f392f8 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/update_application_version.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/update_application_version' + + # Updates the specified application version to have the specified properties. + # + # ==== Options + # * ApplicationName<~String>: The name of the application associated with this version. + # * VersionLabel<~String>: The name of the version to update. + # * Description<~String>: A new description for this release. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_UpdateApplicationVersion.html + # + def update_application_version(options) + request({ + 'Operation' => 'UpdateApplicationVersion', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::UpdateApplicationVersion.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/update_configuration_template.rb b/lib/fog/aws/requests/beanstalk/update_configuration_template.rb new file mode 100644 index 000000000..e69468d66 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/update_configuration_template.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/update_configuration_template' + + # Updates the specified configuration template to have the specified properties or configuration option values. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to include only those that are associated with this application. + # * VersionLabel<~String>: + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateConfigurationTemplate.html + # + def update_configuration_template(options={}) + if option_settings = options.delete('OptionSettings') + options.merge!(Aws.indexed_param('OptionSettings.member.%d', [*option_settings])) + end + if options_to_remove = options.delete('OptionsToRemove') + options.merge!(Aws.indexed_param('OptionsToRemove.member.%d', [*options_to_remove])) + end + request({ + 'Operation' => 'UpdateConfigurationTemplate', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::UpdateConfigurationTemplate.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/update_environment.rb b/lib/fog/aws/requests/beanstalk/update_environment.rb new file mode 100644 index 000000000..d41216af9 --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/update_environment.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/update_environment' + + # Updates the environment description, deploys a new application version, updates the configuration settings + # to an entirely new configuration template, or updates select configuration option values in + # the running environment. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to include only those that are associated with this application. + # * EnvironmentIds + # * EnvironmentNames + # * IncludeDeleted + # * IncludedDeletedBackTo + # * VersionLabel<~String>: + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateEnvironment.html + # + def update_environment(options={}) + if option_settings = options.delete('OptionSettings') + options.merge!(Aws.indexed_param('OptionSettings.member.%d', [*option_settings])) + end + if options_to_remove = options.delete('OptionsToRemove') + options.merge!(Aws.indexed_param('OptionsToRemove.member.%d', [*options_to_remove])) + end + request({ + 'Operation' => 'UpdateEnvironment', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::UpdateEnvironment.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/beanstalk/validate_configuration_settings.rb b/lib/fog/aws/requests/beanstalk/validate_configuration_settings.rb new file mode 100644 index 000000000..9be57f3ee --- /dev/null +++ b/lib/fog/aws/requests/beanstalk/validate_configuration_settings.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class ElasticBeanstalk + class Real + require 'fog/aws/parsers/beanstalk/validate_configuration_settings' + + # Updates the specified configuration template to have the specified properties or configuration option values. + # + # ==== Options + # * ApplicationName<~String>: If specified, Aws Elastic Beanstalk restricts the returned descriptions + # to include only those that are associated with this application. + # * VersionLabel<~String>: + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/elasticbeanstalk/latest/api/API_CreateConfigurationTemplate.html + # + def validate_configuration_settings(options={}) + if option_settings = options.delete('OptionSettings') + options.merge!(Aws.indexed_param('OptionSettings.member.%d', [*option_settings])) + end + request({ + 'Operation' => 'ValidateConfigurationSettings', + :parser => Fog::Parsers::AWS::ElasticBeanstalk::ValidateConfigurationSettings.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/delete_distribution.rb b/lib/fog/aws/requests/cdn/delete_distribution.rb new file mode 100644 index 000000000..4458cc8ad --- /dev/null +++ b/lib/fog/aws/requests/cdn/delete_distribution.rb @@ -0,0 +1,52 @@ +module Fog + module CDN + class Aws + class Real + # Delete a distribution from CloudFront. + # + # @param distribution_id [String] Id of distribution to delete. + # @param etag [String] etag of that distribution from earlier get or put + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/DeleteDistribution.html + + def delete_distribution(distribution_id, etag) + request({ + :expects => 204, + :headers => { 'If-Match' => etag }, + :idempotent => true, + :method => 'DELETE', + :path => "/distribution/#{distribution_id}" + }) + end + end + + class Mock + def delete_distribution(distribution_id, etag) + distribution = self.data[:distributions][distribution_id] + + if distribution + if distribution['ETag'] != etag + Fog::CDN::AWS::Mock.error(:invalid_if_match_version) + end + unless distribution['DistributionConfig']['CallerReference'] + Fog::CDN::AWS::Mock.error(:illegal_update) + end + if distribution['DistributionConfig']['Enabled'] + Fog::CDN::AWS::Mock.error(:distribution_not_disabled) + end + + self.data[:distributions].delete(distribution_id) + self.data[:invalidations].delete(distribution_id) + + response = Excon::Response.new + response.status = 204 + response.body = "x-amz-request-id: #{Fog::AWS::Mock.request_id}" + response + else + Fog::CDN::AWS::Mock.error(:no_such_distribution) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/delete_streaming_distribution.rb b/lib/fog/aws/requests/cdn/delete_streaming_distribution.rb new file mode 100644 index 000000000..5e4174524 --- /dev/null +++ b/lib/fog/aws/requests/cdn/delete_streaming_distribution.rb @@ -0,0 +1,51 @@ +module Fog + module CDN + class Aws + class Real + # Delete a streaming distribution from CloudFront. + # + # @param [String] distribution_id Id of distribution to delete. + # @param [String] etag Etag of that distribution from earlier get or put + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/DeleteStreamingDistribution.html + + def delete_streaming_distribution(distribution_id, etag) + request({ + :expects => 204, + :headers => { 'If-Match' => etag }, + :idempotent => true, + :method => 'DELETE', + :path => "/streaming-distribution/#{distribution_id}" + }) + end + end + + class Mock + def delete_streaming_distribution(distribution_id, etag) + distribution = self.data[:streaming_distributions][distribution_id] + + if distribution + if distribution['ETag'] != etag + Fog::CDN::AWS::Mock.error(:invalid_if_match_version) + end + unless distribution['StreamingDistributionConfig']['CallerReference'] + Fog::CDN::AWS::Mock.error(:illegal_update) + end + if distribution['StreamingDistributionConfig']['Enabled'] + Fog::CDN::AWS::Mock.error(:distribution_not_disabled) + end + + self.data[:streaming_distributions].delete(distribution_id) + + response = Excon::Response.new + response.status = 204 + response.body = "x-amz-request-id: #{Fog::AWS::Mock.request_id}" + response + else + Fog::CDN::AWS::Mock.error(:no_such_streaming_distribution) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/get_distribution.rb b/lib/fog/aws/requests/cdn/get_distribution.rb new file mode 100644 index 000000000..1d37158f9 --- /dev/null +++ b/lib/fog/aws/requests/cdn/get_distribution.rb @@ -0,0 +1,78 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/distribution' + + # Get information about a distribution from CloudFront. + # + # @param distribution_id [String] Id of distribution. + # + # @return [Excon::Response] + # * body [Hash]: + # * S3Origin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # * OriginAccessIdentity [String] - Optional: Used when serving private content. + # or + # * CustomOrigin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'www.example.com'. + # * HTTPPort [Integer] - HTTP port of origin, in [80, 443] or (1024...65535). + # * HTTPSPort [Integer] - HTTPS port of origin, in [80, 443] or (1024...65535). + # * OriginProtocolPolicy [String] - Policy on using http vs https, in ['http-only', 'match-viewer']. + # + # * Id [String] Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Status [String] - Status of distribution. + # * DistributionConfig [Array]: + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # * CNAME [Array] - Array of associated cnames. + # * Comment [String] - Comment associated with distribution. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * InProgressInvalidationBatches [Integer] - Number of invalidation batches in progress. + # * Logging [Hash]: + # * Bucket [String] - Bucket logs are stored in. + # * Prefix [String] - Prefix logs are stored with. + # * Origin [String] - S3 origin bucket. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/GetDistribution.html + + def get_distribution(distribution_id) + request({ + :expects => 200, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::CDN::AWS::Distribution.new, + :path => "/distribution/#{distribution_id}" + }) + end + end + + class Mock + def get_distribution(distribution_id) + response = Excon::Response.new + + distribution = self.data[:distributions][distribution_id] + unless distribution + Fog::CDN::AWS::Mock.error(:no_such_distribution) + end + + if distribution['Status'] == 'InProgress' && (Time.now - Time.parse(distribution['LastModifiedTime']) >= Fog::Mock.delay * 2) + distribution['Status'] = 'Deployed' + end + + etag = Fog::CDN::AWS::Mock.generic_id + response.status = 200 + response.body = { + 'InProgressInvalidationBatches' => 0, + }.merge(distribution.reject { |k,v| k == 'ETag' }) + + response.headers['ETag'] = etag + distribution['ETag'] = etag + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/get_distribution_list.rb b/lib/fog/aws/requests/cdn/get_distribution_list.rb new file mode 100644 index 000000000..e23e3e09e --- /dev/null +++ b/lib/fog/aws/requests/cdn/get_distribution_list.rb @@ -0,0 +1,81 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/get_distribution_list' + + # List information about distributions in CloudFront. + # + # @param options [Hash] Config arguments for list. + # @option options Marker [String] Limits object keys to only those that appear lexicographically after its value. + # @option options MaxItems [Integer] Limits number of object keys returned. + # + # @return [Excon::Response] + # * body [Hash]: + # * IsTruncated [Boolean] - Whether or not the listing is truncated. + # * Marker [String] Marker specified for query. + # * MaxItems [Integer] - Maximum number of keys specified for query. + # * NextMarker [String] - Marker to specify for next page (id of last result of current page). + # * DistributionSummary [Array]: + # * S3Origin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # * OriginAccessIdentity [String] - Optional: Used when serving private content. + # or + # * CustomOrigin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'www.example.com'. + # * HTTPPort [Integer] - HTTP port of origin, in [80, 443] or (1024...65535). + # * HTTPSPort [Integer] - HTTPS port of origin, in [80, 443] or (1024...65535). + # * OriginProtocolPolicy [String] - Policy on using http vs https, in ['http-only', 'match-viewer']. + # * Comment [String] - Comment associated with distribution. + # * CNAME [Array] - Array of associated cnames. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * Id [String] - Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Origin [String] - S3 origin bucket. + # * Status [String] - Status of distribution. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/ListDistributions.html + # + def get_distribution_list(options = {}) + request({ + :expects => 200, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::CDN::AWS::GetDistributionList.new, + :path => "/distribution", + :query => options + }) + end + end + + class Mock + def get_distribution_list(options = {}) + response = Excon::Response.new + response.status = 200 + + distributions = self.data[:distributions].values + + response.body = { + 'Marker' => Fog::Mock.random_hex(16), + 'IsTruncated' => false, + 'MaxItems' => 100, + 'DistributionSummary' => distributions.map { |d| to_distribution_summary(d) } + } + + response + end + + private + + def to_distribution_summary(d) + { + 'DomainName' => d['DomainName'], + 'Id' => d['Id'], + 'LastModifiedTime' => d['LastModifiedTime'] + }.merge(d['DistributionConfig']) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/get_invalidation.rb b/lib/fog/aws/requests/cdn/get_invalidation.rb new file mode 100644 index 000000000..8b03d6cf8 --- /dev/null +++ b/lib/fog/aws/requests/cdn/get_invalidation.rb @@ -0,0 +1,58 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/get_invalidation' + + # Get invalidation. + # + # @param distribution_id [String] Distribution id. + # @param invalidation_id [String] Invalidation id. + # + # @return [Excon::Response] + # * body [Hash]: + # * Id [String] - Invalidation id. + # * Status [String] + # * CreateTime [String] + # * InvalidationBatch [Array]: + # * Path [String] + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/2010-11-01/APIReference/GetInvalidation.html + + def get_invalidation(distribution_id, invalidation_id) + request({ + :expects => 200, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::CDN::AWS::GetInvalidation.new, + :path => "/distribution/#{distribution_id}/invalidation/#{invalidation_id}" + }) + end + end + + class Mock + def get_invalidation(distribution_id, invalidation_id) + distribution = self.data[:distributions][distribution_id] + unless distribution + Fog::CDN::AWS::Mock.error(:no_such_distribution) + end + + invalidation = self.data[:invalidations][distribution_id][invalidation_id] + unless invalidation + Fog::CDN::AWS::Mock.error(:no_such_invalidation) + end + + if invalidation['Status'] == 'InProgress' && (Time.now - Time.parse(invalidation['CreateTime']) >= Fog::Mock.delay * 2) + invalidation['Status'] = 'Completed' + distribution['InProgressInvalidationBatches'] -= 1 + end + + response = Excon::Response.new + response.status = 200 + response.body = invalidation + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/get_invalidation_list.rb b/lib/fog/aws/requests/cdn/get_invalidation_list.rb new file mode 100644 index 000000000..9a9a26ee6 --- /dev/null +++ b/lib/fog/aws/requests/cdn/get_invalidation_list.rb @@ -0,0 +1,76 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/get_invalidation_list' + + # Get invalidation list. + # + # @param options [Hash] Config arguments for list. + # @option options Marker [String] Limits object keys to only those that appear lexicographically after its value. + # @option options MaxItems [Integer] Limits number of object keys returned. + # + # @return [Excon::Response] + # * body [Hash]: + # * IsTruncated [Boolean] - Whether or not the listing is truncated. + # * Marker [String] - Marker specified for query. + # * MaxItems [Integer] - Maximum number of keys specified for query. + # * NextMarker [String] - Marker to specify for next page (id of last result of current page). + # * InvalidationSummary [Array]: + # * Id [String] + # * Status [String] + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/ListInvalidation.html + + def get_invalidation_list(distribution_id, options = {}) + request({ + :expects => 200, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::CDN::AWS::GetInvalidationList.new, + :path => "/distribution/#{distribution_id}/invalidation", + :query => options + }) + end + end + + class Mock + def get_invalidation_list(distribution_id, options = {}) + distribution = self.data[:distributions][distribution_id] + unless distribution + Fog::CDN::AWS::Mock.error(:no_such_distribution) + end + + invalidations = (self.data[:invalidations][distribution_id] || {}).values + + invalidations.each do |invalidation| + if invalidation['Status'] == 'InProgress' && (Time.now - Time.parse(invalidation['CreateTime']) >= Fog::Mock.delay * 2) + invalidation['Status'] = 'Completed' + distribution['InProgressInvalidationBatches'] -= 1 + end + end + + response = Excon::Response.new + response.status = 200 + + response.body = { + 'Marker' => Fog::Mock.random_hex(16), + 'IsTruncated' => false, + 'MaxItems' => 100, + 'InvalidationSummary' => invalidations.map { |i| to_invalidation_summary(i) } + } + response + end + + private + + def to_invalidation_summary(d) + { + 'Id' => d['Id'], + 'Status' => d['Status'] + } + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/get_streaming_distribution.rb b/lib/fog/aws/requests/cdn/get_streaming_distribution.rb new file mode 100644 index 000000000..8e8c6c973 --- /dev/null +++ b/lib/fog/aws/requests/cdn/get_streaming_distribution.rb @@ -0,0 +1,69 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/streaming_distribution' + + # Get information about a streaming distribution from CloudFront. + # + # @param distribution_id [String] Id of distribution. + # + # @return [Excon::Response] + # * body [Hash]: + # * S3Origin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # * OriginAccessIdentity [String] - Optional: Used when serving private content. + # * Id [String] - Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Status [String] - Status of distribution. + # * StreamingDistributionConfig [Array]: + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # * CNAME [Array] - Array of associated cnames. + # * Comment [String] - Comment associated with distribution. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * InProgressInvalidationBatches [Integer] - Number of invalidation batches in progress. + # * Logging [Hash]: + # * Bucket [String] - Bucket logs are stored in. + # * Prefix [String] - Prefix logs are stored with. + # * Origin [String] - S3 origin bucket. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/GetStreamingDistribution.html + + def get_streaming_distribution(distribution_id) + request({ + :expects => 200, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::CDN::AWS::StreamingDistribution.new, + :path => "/streaming-distribution/#{distribution_id}" + }) + end + end + + class Mock + def get_streaming_distribution(distribution_id) + response = Excon::Response.new + + distribution = self.data[:streaming_distributions][distribution_id] + unless distribution + Fog::CDN::AWS::Mock.error(:no_such_streaming_distribution) + end + + if distribution['Status'] == 'InProgress' && (Time.now - Time.parse(distribution['LastModifiedTime']) >= Fog::Mock.delay * 2) + distribution['Status'] = 'Deployed' + end + + etag = Fog::CDN::AWS::Mock.generic_id + response.status = 200 + response.body = distribution.reject { |k,v| k == 'ETag' } + + response.headers['ETag'] = etag + distribution['ETag'] = etag + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/get_streaming_distribution_list.rb b/lib/fog/aws/requests/cdn/get_streaming_distribution_list.rb new file mode 100644 index 000000000..148da3ced --- /dev/null +++ b/lib/fog/aws/requests/cdn/get_streaming_distribution_list.rb @@ -0,0 +1,81 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/get_streaming_distribution_list' + + # List information about distributions in CloudFront. + # + # @param options [Hash] Config arguments for list. + # @option options Marker [String] Limits object keys to only those that appear lexicographically after its value. + # @option options MaxItems [Integer] Limits number of object keys returned. + # + # @return [Excon::Response] + # * body [Hash]: + # * IsTruncated [Boolean] - Whether or not the listing is truncated. + # * Marker [String] - Marker specified for query. + # * MaxItems [Integer] - Maximum number of keys specified for query. + # * NextMarker [String] - Marker to specify for next page (id of last result of current page). + # * StreamingDistributionSummary [Array]: + # * S3Origin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # * OriginAccessIdentity [String] - Optional: Used when serving private content. + # or + # * CustomOrigin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'www.example.com'. + # * HTTPPort [Integer] - HTTP port of origin, in [80, 443] or (1024...65535). + # * HTTPSPort [Integer] - HTTPS port of origin, in [80, 443] or (1024...65535). + # * OriginProtocolPolicy [String] - Policy on using http vs https, in ['http-only', 'match-viewer']. + # * Comment [String] - Comment associated with distribution. + # * CNAME [Array] - Array of associated cnames. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * Id [String] - Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Origin [String] - S3 origin bucket. + # * Status [String] - Status of distribution. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/ListStreamingDistributions.html + + def get_streaming_distribution_list(options = {}) + request({ + :expects => 200, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::CDN::AWS::GetStreamingDistributionList.new, + :path => "/streaming-distribution", + :query => options + }) + end + end + + class Mock + def get_streaming_distribution_list(options = {}) + response = Excon::Response.new + response.status = 200 + + distributions = self.data[:streaming_distributions].values + + response.body = { + 'Marker' => Fog::Mock.random_hex(16), + 'IsTruncated' => false, + 'MaxItems' => 100, + 'StreamingDistributionSummary' => distributions.map { |d| to_streaming_distribution_summary(d) } + } + + response + end + + private + + def to_streaming_distribution_summary(d) + { + 'DomainName' => d['DomainName'], + 'Id' => d['Id'], + 'LastModifiedTime' => d['LastModifiedTime'] + }.merge(d['StreamingDistributionConfig']) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/post_distribution.rb b/lib/fog/aws/requests/cdn/post_distribution.rb new file mode 100644 index 000000000..45334931e --- /dev/null +++ b/lib/fog/aws/requests/cdn/post_distribution.rb @@ -0,0 +1,130 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/distribution' + + # Create a new distribution in CloudFront. + # + # @param options [Hash] Config for distribution. + # + # REQUIRED: + # * S3Origin [Hash]: + # * DNSName [String] Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # * OriginAccessIdentity [String] Optional: used when serving private content. + # or + # * CustomOrigin [Hash]: + # * DNSName [String] Origin to associate with distribution, ie 'www.example.com'. + # * HTTPPort [Integer] Optional HTTP port of origin, in [80, 443] or (1024...65535), defaults to 80. + # * HTTPSPort [Integer] Optional HTTPS port of origin, in [80, 443] or (1024...65535), defaults to 443. + # * OriginProtocolPolicy [String] Policy on using http vs https, in ['http-only', 'match-viewer']. + # OPTIONAL: + # * CallerReference [String] Used to prevent replay, defaults to Time.now.to_i.to_s. + # * Comment [String] Optional comment about distribution. + # * CNAME [Array] Optional array of strings to set as CNAMEs. + # * DefaultRootObject [String] Optional default object to return for '/'. + # * Enabled [Boolean] Whether or not distribution should accept requests, defaults to true. + # * Logging [Hash]: Optional logging config. + # * Bucket [String] Bucket to store logs in, ie 'mylogs.s3.amazonaws.com'. + # * Prefix [String] Optional prefix for log filenames, ie 'myprefix/'. + # * OriginAccessIdentity [String] Used for serving private content, in format 'origin-access-identity/cloudfront/ID'. + # * RequiredProtocols [String] Optional, set to 'https' to force https connections. + # * TrustedSigners [Array] Optional grant of rights to up to 5 aws accounts to generate signed URLs for private content, elements are either 'Self' for your own account or an Aws Account Number. + # + # @return [Excon::Response] + # * body [Hash]: + # * DomainName [String] - Domain name of distribution. + # * Id [String] - Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Status [String] - Status of distribution. + # * DistributionConfig [Array]: + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # * CNAME [Array] - Array of associated cnames. + # * Comment [String] - Comment associated with distribution. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * Logging [Hash]: + # * Bucket [String] - Bucket logs are stored in. + # * Prefix [String] - Prefix logs are stored with. + # * Origin [String] - S3 origin bucket. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/CreateDistribution.html + + def post_distribution(options = {}) + options['CallerReference'] = Time.now.to_i.to_s + data = '' + data << "" + for key, value in options + case value + when Array + for item in value + data << "<#{key}>#{item}" + end + when Hash + data << "<#{key}>" + for inner_key, inner_value in value + data << "<#{inner_key}>#{inner_value}" + end + data << "" + else + data << "<#{key}>#{value}" + end + end + data << "" + request({ + :body => data, + :expects => 201, + :headers => { 'Content-Type' => 'text/xml' }, + :idempotent => true, + :method => 'POST', + :parser => Fog::Parsers::CDN::AWS::Distribution.new, + :path => "/distribution" + }) + end + end + + class Mock + require 'time' + + def post_distribution(options = {}) + if self.data[:distributions].values.any? { |d| (d['CNAME'] & (options['CNAME']||[])).empty? } + Fog::CDN::AWS::Mock.error(:invalid_argument, 'CNAME is already in use') + end + + response = Excon::Response.new + + response.status = 201 + options['CallerReference'] = Time.now.to_i.to_s + + dist_id = Fog::CDN::AWS::Mock.distribution_id + + distribution = { + 'DomainName' => Fog::CDN::AWS::Mock.domain_name, + 'Id' => dist_id, + 'Status' => 'InProgress', + 'LastModifiedTime' => Time.now.utc.iso8601, + 'InProgressInvalidationBatches' => 0, + 'DistributionConfig' => { + 'CallerReference' => options['CallerReference'], + 'CNAME' => options['CNAME'] || [], + 'Comment' => options['Comment'], + 'Enabled' => options['Enabled'], + 'Logging' => { + 'Bucket' => options['Bucket'], + 'Prefix' => options['Prefix'] + }, + 'S3Origin' => options['S3Origin'], + 'CustomOrigin' => options['CustomOrigin'], + 'TrustedSigners' => options['TrustedSigners'] || [] + } + } + + self.data[:distributions][dist_id] = distribution + + response.body = distribution + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/post_invalidation.rb b/lib/fog/aws/requests/cdn/post_invalidation.rb new file mode 100644 index 000000000..50e7ff908 --- /dev/null +++ b/lib/fog/aws/requests/cdn/post_invalidation.rb @@ -0,0 +1,75 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/post_invalidation' + + # List information about distributions in CloudFront. + # + # @param distribution_id [String] Id of distribution for invalidations. + # @param paths [Array] Array of string paths to objects to invalidate. + # @param caller_reference [String] Used to prevent replay, defaults to Time.now.to_i.to_s. + # + # @return [Excon::Response] + # * body [Hash]: + # * Id [String] - Id of invalidation. + # * Status [String] - Status of invalidation. + # * CreateTime [Integer] - Time of invalidation creation. + # * InvalidationBatch [Array]: + # * Path [Array] - Array of strings of objects to invalidate. + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/CreateInvalidation.html + + def post_invalidation(distribution_id, paths, caller_reference = Time.now.to_i.to_s) + body = '' + body << "" + for path in [*paths] + body << "" << path << "" + end + body << "" << caller_reference << "" + body << "" + request({ + :body => body, + :expects => 201, + :headers => {'Content-Type' => 'text/xml'}, + :idempotent => true, + :method => 'POST', + :parser => Fog::Parsers::CDN::AWS::PostInvalidation.new, + :path => "/distribution/#{distribution_id}/invalidation" + }) + end + end + + class Mock + def post_invalidation(distribution_id, paths, caller_reference = Time.now.to_i.to_s) + distribution = self.data[:distributions][distribution_id] + if distribution + invalidation_id = Fog::CDN::AWS::Mock.distribution_id + invalidation = { + 'Id' => invalidation_id, + 'Status' => 'InProgress', + 'CreateTime' => Time.now.utc.iso8601, + 'InvalidationBatch' => { + 'CallerReference' => caller_reference, + 'Path' => paths + } + } + + distribution['InProgressInvalidationBatches'] += 1 + + self.data[:invalidations][distribution_id] ||= {} + self.data[:invalidations][distribution_id][invalidation_id] = invalidation + + response = Excon::Response.new + response.status = 201 + response.body = invalidation + response + else + Fog::CDN::AWS::Mock.error(:no_such_distribution) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/post_streaming_distribution.rb b/lib/fog/aws/requests/cdn/post_streaming_distribution.rb new file mode 100644 index 000000000..811279138 --- /dev/null +++ b/lib/fog/aws/requests/cdn/post_streaming_distribution.rb @@ -0,0 +1,115 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/streaming_distribution' + + # Create a new streaming distribution in CloudFront. + # + # @param options [Hash] Config for distribution. + # + # REQUIRED: + # * S3Origin [Hash]: + # * DNSName [String] Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # OPTIONAL: + # * CallerReference [String] Used to prevent replay, defaults to Time.now.to_i.to_s. + # * Comment [String] Optional comment about distribution. + # * CNAME [Array] Optional array of strings to set as CNAMEs. + # * Enabled [Boolean] Whether or not distribution should accept requests, defaults to true. + # * Logging [Hash]: Optional logging config. + # * Bucket [String] Bucket to store logs in, ie 'mylogs.s3.amazonaws.com'. + # * Prefix [String] Optional prefix for log filenames, ie 'myprefix/'. + # + # @return [Excon::Response] + # * body[Hash]: + # * Id [String] - Id of distribution. + # * Status'[String] - Status of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * DomainName [String] - Domain name of distribution. + # * StreamingDistributionConfig [Array]: + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # * CNAME [Array] - Array of associated cnames. + # * Comment [String] - Comment associated with distribution. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * Logging [Hash]: + # * Bucket [String] - Bucket logs are stored in. + # * Prefix [String] - Prefix logs are stored with. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/CreateStreamingDistribution.html + + def post_streaming_distribution(options = {}) + options['CallerReference'] = Time.now.to_i.to_s + data = '' + data << "" + for key, value in options + case value + when Array + for item in value + data << "<#{key}>#{item}" + end + when Hash + data << "<#{key}>" + for inner_key, inner_value in value + data << "<#{inner_key}>#{inner_value}" + end + data << "" + else + data << "<#{key}>#{value}" + end + end + data << "" + request({ + :body => data, + :expects => 201, + :headers => { 'Content-Type' => 'text/xml' }, + :idempotent => true, + :method => 'POST', + :parser => Fog::Parsers::CDN::AWS::StreamingDistribution.new, + :path => "/streaming-distribution" + }) + end + end + + class Mock + require 'time' + + def post_streaming_distribution(options = {}) + if self.data[:streaming_distributions].values.any? { |d| (d['CNAME'] & (options['CNAME']||[])).empty? } + Fog::CDN::AWS::Mock.error(:invalid_argument, 'CNAME is already in use') + end + + response = Excon::Response.new + + response.status = 201 + options['CallerReference'] = Time.now.to_i.to_s + + dist_id = Fog::CDN::AWS::Mock.distribution_id + + distribution = { + 'DomainName' => Fog::CDN::AWS::Mock.domain_name, + 'Id' => dist_id, + 'Status' => 'InProgress', + 'LastModifiedTime' => Time.now.utc.iso8601, + 'StreamingDistributionConfig' => { + 'CallerReference' => options['CallerReference'], + 'CNAME' => options['CNAME'] || [], + 'Comment' => options['Comment'], + 'Enabled' => options['Enabled'], + 'Logging' => { + 'Bucket' => options['Bucket'], + 'Prefix' => options['Prefix'] + }, + 'S3Origin' => options['S3Origin'], + 'TrustedSigners' => options['TrustedSigners'] || [] + } + } + + self.data[:streaming_distributions][dist_id] = distribution + + response.body = distribution + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/put_distribution_config.rb b/lib/fog/aws/requests/cdn/put_distribution_config.rb new file mode 100644 index 000000000..2a230b35d --- /dev/null +++ b/lib/fog/aws/requests/cdn/put_distribution_config.rb @@ -0,0 +1,116 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/distribution' + + # Update a distribution in CloudFront. + # + # @param distribution_id [String] Id of distribution to update config for. + # @param options [Hash] Config for distribution. + # + # REQUIRED: + # * S3Origin [Hash]: + # * DNSName [String] - origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # * OriginAccessIdentity [String] - Optional: Used when serving private content. + # or + # * CustomOrigin [Hash]: + # * DNSName [String] - Origin to associate with distribution, ie 'www.example.com'. + # * HTTPPort [Integer] - HTTP port of origin, in [80, 443] or (1024...65535). + # * HTTPSPort [Integer] - HTTPS port of origin, in [80, 443] or (1024...65535). + # * OriginProtocolPolicy [String] - Policy on using http vs https, in ['http-only', 'match-viewer']. + # OPTIONAL: + # * CallerReference [String] Used to prevent replay, defaults to Time.now.to_i.to_s. + # * Comment [String] Optional comment about distribution. + # * CNAME [Array] Optional array of strings to set as CNAMEs. + # * DefaultRootObject [String] Optional default object to return for '/'. + # * Enabled [Boolean] Whether or not distribution should accept requests, defaults to true. + # * Logging [Hash]: Optional logging config. + # * Bucket [String] Bucket to store logs in, ie 'mylogs.s3.amazonaws.com'. + # * Prefix [String] Optional prefix for log filenames, ie 'myprefix/'. + # * OriginAccessIdentity [String] Used for serving private content, in format 'origin-access-identity/cloudfront/ID'. + # * RequiredProtocols [String] Optional, set to 'https' to force https connections. + # * TrustedSigners [Array] Optional grant of rights to up to 5 aws accounts to generate signed URLs for private content, elements are either 'Self' for your own account or an Aws Account Number. + # + # @return [Excon::Response] + # * body [Hash]: + # * DomainName [String]: Domain name of distribution. + # * Id [String] - Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Status [String] - Status of distribution. + # * DistributionConfig [Array]: + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # * CNAME [Array] - Array of associated cnames. + # * Comment [String] - Comment associated with distribution. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * Logging [Hash]: + # * Bucket [String] - Bucket logs are stored in. + # * Prefix [String] - Prefix logs are stored with. + # * Origin [String] - S3 origin bucket. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/CreateDistribution.html + + def put_distribution_config(distribution_id, etag, options = {}) + data = '' + data << "" + for key, value in options + case value + when Array + for item in value + data << "<#{key}>#{item}" + end + when Hash + data << "<#{key}>" + for inner_key, inner_value in value + data << "<#{inner_key}>#{inner_value}" + end + data << "" + else + data << "<#{key}>#{value}" + end + end + data << "" + request({ + :body => data, + :expects => 200, + :headers => { + 'Content-Type' => 'text/xml', + 'If-Match' => etag + }, + :idempotent => true, + :method => 'PUT', + :parser => Fog::Parsers::CDN::AWS::Distribution.new, + :path => "/distribution/#{distribution_id}/config" + }) + end + end + + class Mock + def put_distribution_config(distribution_id, etag, options = {}) + distribution = self.data[:distributions][distribution_id] + + if distribution + if distribution['ETag'] != etag + Fog::CDN::AWS::Mock.error(:invalid_if_match_version) + end + unless distribution['DistributionConfig']['CallerReference'] + Fog::CDN::AWS::Mock.error(:illegal_update) + end + + distribution['DistributionConfig'].merge!(options) + distribution['Status'] = 'InProgress' + + response = Excon::Response.new + response.status = 200 + response.headers['ETag'] = Fog::CDN::AWS::Mock.generic_id + response.body = distribution.merge({ 'LastModifiedTime' => Time.now.utc.iso8601 }).reject{ |k,v| k == 'ETag' } + response + else + Fog::CDN::AWS::Mock.error(:no_such_distribution) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/cdn/put_streaming_distribution_config.rb b/lib/fog/aws/requests/cdn/put_streaming_distribution_config.rb new file mode 100644 index 000000000..82740e5f4 --- /dev/null +++ b/lib/fog/aws/requests/cdn/put_streaming_distribution_config.rb @@ -0,0 +1,105 @@ +module Fog + module CDN + class Aws + class Real + require 'fog/aws/parsers/cdn/streaming_distribution' + + # Update a streaming distribution in CloudFront. + # + # @param distribution_id [String] - Id of distribution to update config for. + # @param options [Hash] - Config for distribution. + # + # REQUIRED: + # * S3Origin [Hash]: + # * DNSName [String] Origin to associate with distribution, ie 'mybucket.s3.amazonaws.com'. + # OPTIONAL: + # @option options CallerReference [String] Used to prevent replay, defaults to Time.now.to_i.to_s + # @option options Comment [String] Optional comment about distribution + # @option options CNAME [Array] Optional array of strings to set as CNAMEs + # @option options Enabled [Boolean] Whether or not distribution should accept requests, defaults to true + # @option options Logging [Hash]: Optional logging config + # * Bucket [String] Bucket to store logs in, ie 'mylogs.s3.amazonaws.com' + # * Prefix String] Optional prefix for log filenames, ie 'myprefix/' + # + # @return [Excon::Response] + # * body [Hash]: + # * DomainName [String] - Domain name of distribution. + # * Id [String] - Id of distribution. + # * LastModifiedTime [String] - Timestamp of last modification of distribution. + # * Status [String] - Status of distribution. + # * StreamingDistributionConfig [Array]: + # * CallerReference [String] - Used to prevent replay, defaults to Time.now.to_i.to_s. + # * CNAME [Array] - Array of associated cnames. + # * Comment [String] - Comment associated with distribution. + # * Enabled [Boolean] - Whether or not distribution is enabled. + # * Logging [Hash]: + # * Bucket [String] - Bucket logs are stored in. + # * Prefix [String] - Prefix logs are stored with. + # * Origin [String] - S3 origin bucket. + # * TrustedSigners [Array] - Trusted signers. + # + # @see http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/PutStreamingDistribution.html + + def put_streaming_distribution_config(distribution_id, etag, options = {}) + data = '' + data << "" + for key, value in options + case value + when Array + for item in value + data << "<#{key}>#{item}" + end + when Hash + data << "<#{key}>" + for inner_key, inner_value in value + data << "<#{inner_key}>#{inner_value}" + end + data << "" + else + data << "<#{key}>#{value}" + end + end + data << "" + request({ + :body => data, + :expects => 200, + :headers => { + 'Content-Type' => 'text/xml', + 'If-Match' => etag + }, + :idempotent => true, + :method => 'PUT', + :parser => Fog::Parsers::CDN::AWS::StreamingDistribution.new, + :path => "/streaming-distribution/#{distribution_id}/config" + }) + end + end + + class Mock + def put_streaming_distribution_config(distribution_id, etag, options = {}) + distribution = self.data[:streaming_distributions][distribution_id] + + if distribution + if distribution['ETag'] != etag + Fog::CDN::AWS::Mock.error(:invalid_if_match_version) + end + unless distribution['StreamingDistributionConfig']['CallerReference'] + Fog::CDN::AWS::Mock.error(:illegal_update) + end + + distribution['StreamingDistributionConfig'].merge!(options) + distribution['Status'] = 'InProgress' + + response = Excon::Response.new + response.status = 200 + response.headers['ETag'] = Fog::CDN::AWS::Mock.generic_id + response.body = distribution.merge({ 'LastModifiedTime' => Time.now.utc.iso8601 }).reject{ |k,v| k == 'ETag' } + response + else + Fog::CDN::AWS::Mock.error(:no_such_streaming_distribution) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/create_stack.rb b/lib/fog/aws/requests/cloud_formation/create_stack.rb new file mode 100644 index 000000000..6cc8f657a --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/create_stack.rb @@ -0,0 +1,88 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/create_stack' + + # Create a stack. + # + # * stack_name [String] Name of the stack to create. + # * options [Hash]: + # * TemplateBody [String] Structure containing the template body. + # or (one of the two Template parameters is required) + # * TemplateURL [String] URL of file containing the template body. + # * DisableRollback [Boolean] Controls rollback on stack creation failure, defaults to false. + # * NotificationARNs [Array] List of SNS topics to publish events to. + # * Parameters [Hash] Hash of providers to supply to template + # * TimeoutInMinutes [Integer] Minutes to wait before status is set to CREATE_FAILED + # * Capabilities [Array] List of capabilties the stack is granted. Currently CAPABILITY_IAM for allowing the creation of IAM resources + # + # @return [Excon::Response]: + # * body [Hash: + # * StackId [String] - Id of the new stack + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_CreateStack.html + + def create_stack(stack_name, options = {}) + params = { + 'StackName' => stack_name, + } + + if options['DisableRollback'] + params['DisableRollback'] = options['DisableRollback'] + end + + if options['NotificationARNs'] + params.merge!(Fog::AWS.indexed_param("NotificationARNs.member", [*options['NotificationARNs']])) + end + + if options['Parameters'] + options['Parameters'].keys.each_with_index do |key, index| + index += 1 # params are 1-indexed + params.merge!({ + "Parameters.member.#{index}.ParameterKey" => key, + "Parameters.member.#{index}.ParameterValue" => options['Parameters'][key] + }) + end + end + + num_tags = 0 + if options['Tags'] + options['Tags'].keys.each_with_index do |key, index| + index += 1 # tags are 1-indexed + num_tags += 1 # 10 tag max + + params.merge!({ + "Tags.member.#{index}.Key" => key, + "Tags.member.#{index}.Value" => options['Tags'][key] + }) + end + end + + if num_tags > 10 + raise ArgumentError.new("a maximum of 10 tags can be specified <#{num_tags}>") + end + + if options['TemplateBody'] + params['TemplateBody'] = options['TemplateBody'] + elsif options['TemplateURL'] + params['TemplateURL'] = options['TemplateURL'] + end + + if options['TimeoutInMinutes'] + params['TimeoutInMinutes'] = options['TimeoutInMinutes'] + end + + if options['Capabilities'] + params.merge!(Fog::AWS.indexed_param("Capabilities.member", [*options['Capabilities']])) + end + + request({ + 'Action' => 'CreateStack', + :parser => Fog::Parsers::AWS::CloudFormation::CreateStack.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/delete_stack.rb b/lib/fog/aws/requests/cloud_formation/delete_stack.rb new file mode 100644 index 000000000..a16166c2a --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/delete_stack.rb @@ -0,0 +1,25 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/basic' + + # Delete a stack. + # + # @param stack_name String] Name of the stack to create. + # + # @return [Excon::Response] + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_DeleteStack.html + + def delete_stack(stack_name) + request( + 'Action' => 'DeleteStack', + 'StackName' => stack_name, + :parser => Fog::Parsers::AWS::CloudFormation::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/describe_stack_events.rb b/lib/fog/aws/requests/cloud_formation/describe_stack_events.rb new file mode 100644 index 000000000..5ef2c3d34 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/describe_stack_events.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/describe_stack_events' + + # Describe stack events. + # + # @param stack_name [String] stack name to return events for. + # @param options [Hash] + # @option options NextToken [String] Identifies the start of the next list of events, if there is one. + # + # @return [Excon::Response] + # * body [Hash]: + # * StackEvents [Array] - Matching resources + # * event [Hash]: + # * EventId [String] - + # * StackId [String] - + # * StackName [String] - + # * LogicalResourceId [String] - + # * PhysicalResourceId [String] - + # * ResourceType [String] - + # * Timestamp [Time] - + # * ResourceStatus [String] - + # * ResourceStatusReason [String] - + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_DescribeStackEvents.html + + def describe_stack_events(stack_name, options = {}) + request({ + 'Action' => 'DescribeStackEvents', + 'StackName' => stack_name, + :parser => Fog::Parsers::AWS::CloudFormation::DescribeStackEvents.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/describe_stack_resources.rb b/lib/fog/aws/requests/cloud_formation/describe_stack_resources.rb new file mode 100644 index 000000000..8c9ddeb05 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/describe_stack_resources.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/describe_stack_resources' + + # Describe stack resources. + # + # @param options Hash]: + # * PhysicalResourceId [String] name or unique identifier that corresponds to a physical instance ID + # or (one of PhysicalResourceId and StackName is required) + # * StackName [String] Only return events related to this stack name + # * LogicalResourceId [String] Logical name of the resource as specified in the template + # + # @return [Excon::Response] + # * body [Hash]: + # * StackResources [Array] - Matching resources + # * resource [Hash]: + # * StackId [String] - + # * StackName [String] - + # * LogicalResourceId [String] - + # * PhysicalResourceId [String] - + # * ResourceType [String] - + # * Timestamp [Time] - + # * ResourceStatus [String] - + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_DescribeStackResources.html + + def describe_stack_resources(options = {}) + request({ + 'Action' => 'DescribeStackResources', + :parser => Fog::Parsers::AWS::CloudFormation::DescribeStackResources.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/describe_stacks.rb b/lib/fog/aws/requests/cloud_formation/describe_stacks.rb new file mode 100644 index 000000000..4ed91adf2 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/describe_stacks.rb @@ -0,0 +1,37 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/describe_stacks' + + # Describe stacks. + # + # @param options [Hash] + # @option options StackName [String] Name of the stack to describe. + # + # @return [Excon::Response] + # * body [Hash]: + # * Stacks [Array] - Matching stacks + # * stack [Hash]: + # * StackName [String] - + # * StackId [String] - + # * CreationTime [String] - + # * StackStatus [String] - + # * DisableRollback [String] - + # * Outputs [Array] - + # * output [Hash]: + # * OutputKey [String] - + # * OutputValue [String] - + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_DescribeStacks.html + + def describe_stacks(options = {}) + request({ + 'Action' => 'DescribeStacks', + :parser => Fog::Parsers::AWS::CloudFormation::DescribeStacks.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/get_template.rb b/lib/fog/aws/requests/cloud_formation/get_template.rb new file mode 100644 index 000000000..ce5c25f41 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/get_template.rb @@ -0,0 +1,27 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/get_template' + + # Describe stacks. + # + # @param stack_name [String] stack name to get template from + # + # @return [Excon::Response] + # * body [Hash]: + # * TemplateBody [String] - structure containing the template body (json) + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_GetTemplate.html + + def get_template(stack_name) + request( + 'Action' => 'GetTemplate', + 'StackName' => stack_name, + :parser => Fog::Parsers::AWS::CloudFormation::GetTemplate.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/list_stack_resources.rb b/lib/fog/aws/requests/cloud_formation/list_stack_resources.rb new file mode 100644 index 000000000..19cbdcc82 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/list_stack_resources.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/list_stack_resources' + + # List stack resources. + # + # @param options [Hash] + # @option options StackName [String] Name of the stack to describe. + # + # @return [Excon::Response] + # * body [Hash]: + # * StackResourceSummaries [Array] - Matching stacks + # * resources [Hash]: + # * ResourceStatus [String] - + # * LogicalResourceId [String] - + # * PhysicalResourceId [String] - + # * ResourceType [String] - + # * LastUpdatedTimestamp [Time] - + # + # + # @see http://docs.aws.amazon.com/AwsCloudFormation/latest/APIReference/API_ListStacks.html + + def list_stack_resources(options = {}) + request({ + 'Action' => 'ListStackResources', + :parser => Fog::Parsers::AWS::CloudFormation::ListStackResources.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/list_stacks.rb b/lib/fog/aws/requests/cloud_formation/list_stacks.rb new file mode 100644 index 000000000..eb5c7fab2 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/list_stacks.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/list_stacks' + + # List stacks. + # + # @param options [Hash] + # + # @return [Excon::Response] + # * body [Hash]: + # * StackSummaries [Array] - Matching stacks + # * stack [Hash]: + # * StackId [String] - + # * StackName [String] - + # * TemplateDescription [String] - + # * CreationTime [Time] - + # * DeletionTime [Time] - + # * StackStatus [String] - + # * DeletionTime [String] - + # + # + # @see http://docs.aws.amazon.com/AwsCloudFormation/latest/APIReference/API_ListStacks.html + + def list_stacks(options = {}) + request({ + 'Action' => 'ListStacks', + :parser => Fog::Parsers::AWS::CloudFormation::ListStacks.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/update_stack.rb b/lib/fog/aws/requests/cloud_formation/update_stack.rb new file mode 100644 index 000000000..75827852a --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/update_stack.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/update_stack' + + # Update a stack. + # + # @param [String] stack_name Name of the stack to update. + # @param [Hash] options + # * TemplateBody [String] Structure containing the template body. + # or (one of the two Template parameters is required) + # * TemplateURL [String] URL of file containing the template body. + # * Parameters [Hash] Hash of providers to supply to template. + # * Capabilities [Array] List of capabilties the stack is granted. Currently CAPABILITY_IAM for allowing the creation of IAM resources. + # + # @return [Excon::Response] + # * body [Hash]: + # * StackId [String] - Id of the stack being updated + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_UpdateStack.html + # + def update_stack(stack_name, options = {}) + params = { + 'StackName' => stack_name, + } + + if options['Parameters'] + options['Parameters'].keys.each_with_index do |key, index| + index += 1 # params are 1-indexed + params.merge!({ + "Parameters.member.#{index}.ParameterKey" => key, + "Parameters.member.#{index}.ParameterValue" => options['Parameters'][key] + }) + end + end + + if options['TemplateBody'] + params['TemplateBody'] = options['TemplateBody'] + elsif options['TemplateURL'] + params['TemplateURL'] = options['TemplateURL'] + end + + if options['Capabilities'] + params.merge!(Fog::AWS.indexed_param("Capabilities.member", [*options['Capabilities']])) + end + + request({ + 'Action' => 'UpdateStack', + :parser => Fog::Parsers::AWS::CloudFormation::UpdateStack.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_formation/validate_template.rb b/lib/fog/aws/requests/cloud_formation/validate_template.rb new file mode 100644 index 000000000..c403f7945 --- /dev/null +++ b/lib/fog/aws/requests/cloud_formation/validate_template.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class CloudFormation + class Real + require 'fog/aws/parsers/cloud_formation/validate_template' + + # Describe stacks. + # + # @param [Hash] options + # @option options [String] TemplateBody template structure + # @option options [String] TemplateURL template url + # + # @return [Excon::Response] + # * body [Hash]: + # * Description [String] - description found within the template + # * Parameters [String] - list of template parameter structures + # + # @see http://docs.amazonwebservices.com/AwsCloudFormation/latest/APIReference/API_ValidateTemplate.html + # + def validate_template(options = {}) + request({ + 'Action' => 'ValidateTemplate', + :parser => Fog::Parsers::AWS::CloudFormation::ValidateTemplate.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/delete_alarms.rb b/lib/fog/aws/requests/cloud_watch/delete_alarms.rb new file mode 100644 index 000000000..0de271dfa --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/delete_alarms.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/delete_alarms' + + # Delete a list of alarms + # ==== Options + # * AlarmNames<~Array>: A list of alarms to be deleted + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_DeleteAlarms.html + # + + def delete_alarms(alarm_names) + options = {} + options.merge!(Aws.indexed_param('AlarmNames.member.%d', [*alarm_names])) + request({ + 'Action' => 'DeleteAlarms', + :parser => Fog::Parsers::AWS::CloudWatch::DeleteAlarms.new + }.merge(options)) + end + end + + class Mock + def delete_alarms(alarm_names) + [*alarm_names].each do |alarm_name| + unless data[:metric_alarms].key?(alarm_name) + raise Fog::AWS::AutoScaling::NotFound, "The alarm '#{alarm_name}' does not exist." + end + end + + [*alarm_names].each { |alarm_name| data[:metric_alarms].delete(alarm_name) } + response = Excon::Response.new + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/describe_alarm_history.rb b/lib/fog/aws/requests/cloud_watch/describe_alarm_history.rb new file mode 100644 index 000000000..ccb1e7a97 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/describe_alarm_history.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/describe_alarm_history' + + # Retrieves history for the specified alarm + # ==== Options + # * AlarmName<~String>: The name of the alarm + # * EndDate<~DateTime>: The ending date to retrieve alarm history + # * HistoryItemType<~String>: The type of alarm histories to retrieve + # * MaxRecords<~Integer>: The maximum number of alarm history records to retrieve + # * NextToken<~String> The token returned by a previous call to indicate that there is more data available + # * StartData<~DateTime>: The starting date to retrieve alarm history + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_DescribeAlarmHistory.html + # + + def describe_alarm_history(options={}) + request({ + 'Action' => 'DescribeAlarmHistory', + :parser => Fog::Parsers::AWS::CloudWatch::DescribeAlarmHistory.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/describe_alarms.rb b/lib/fog/aws/requests/cloud_watch/describe_alarms.rb new file mode 100644 index 000000000..a19ed605b --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/describe_alarms.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/describe_alarms' + + # Retrieves alarms with the specified names + # ==== Options + # * ActionPrefix<~String>: The action name prefix + # * AlarmNamePrefix<~String>: The alarm name prefix. + # AlarmNames cannot be specified if this parameter is specified + # * AlarmNames<~Array>: A list of alarm names to retrieve information for. + # * MaxRecords<~Integer>: The maximum number of alarm descriptions to retrieve + # * NextToken<~String>: The token returned by a previous call to indicate that there is more data available + # * NextToken<~String> The token returned by a previous call to indicate that there is more data available + # * StateValue<~String>: The state value to be used in matching alarms + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_DescribeAlarms.html + # + + def describe_alarms(options={}) + if alarm_names = options.delete('AlarmNames') + options.merge!(Aws.indexed_param('AlarmNames.member.%d', [*alarm_names])) + end + request({ + 'Action' => 'DescribeAlarms', + :parser => Fog::Parsers::AWS::CloudWatch::DescribeAlarms.new + }.merge(options)) + end + end + + class Mock + def describe_alarms(options={}) + results = { 'MetricAlarms' => [] } + data[:metric_alarms].each do |alarm_name, alarm_data| + results['MetricAlarms'] << { + 'AlarmName' => alarm_name + }.merge!(alarm_data) + end + response = Excon::Response.new + response.status = 200 + response.body = { + 'DescribeAlarmsResult' => results, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/describe_alarms_for_metric.rb b/lib/fog/aws/requests/cloud_watch/describe_alarms_for_metric.rb new file mode 100644 index 000000000..551359675 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/describe_alarms_for_metric.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/describe_alarms_for_metric' + + # Retrieves all alarms for a single metric + # ==== Options + # * Dimensions<~Array>: a list of dimensions to filter against + # Name : The name of the dimension + # Value : The value to filter against + # * MetricName<~String>: The name of the metric + # * Namespace<~String>: The namespace of the metric + # * Period<~Integer>: The period in seconds over which the statistic is applied + # * Statistics<~String>: The statistic for the metric + # * Unit<~String> The unit for the metric + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_DescribeAlarms.html + # + + def describe_alarms_for_metric(options) + if dimensions = options.delete('Dimensions') + options.merge!(Aws.indexed_param('Dimensions.member.%d.Name', dimensions.map {|dimension| dimension['Name']})) + options.merge!(Aws.indexed_param('Dimensions.member.%d.Value', dimensions.map {|dimension| dimension['Value']})) + end + request({ + 'Action' => 'DescribeAlarmsForMetric', + :parser => Fog::Parsers::AWS::CloudWatch::DescribeAlarmsForMetric.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/disable_alarm_actions.rb b/lib/fog/aws/requests/cloud_watch/disable_alarm_actions.rb new file mode 100644 index 000000000..518537f46 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/disable_alarm_actions.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/disable_alarm_actions' + + # Disables actions for the specified alarms + # ==== Options + # * AlarmNames<~Array>: The names of the alarms to disable actions for + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_DisableAlarmActions.html + # + + def disable_alarm_actions(alarm_names) + options = {} + options.merge!(Aws.indexed_param('AlarmNames.member.%d', [*alarm_names])) + request({ + 'Action' => 'DisableAlarmActions', + :parser => Fog::Parsers::AWS::CloudWatch::DisableAlarmActions.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/enable_alarm_actions.rb b/lib/fog/aws/requests/cloud_watch/enable_alarm_actions.rb new file mode 100644 index 000000000..d0135d484 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/enable_alarm_actions.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/enable_alarm_actions' + + # Enables actions for the specified alarms + # ==== Options + # * AlarmNames<~Array>: The names of the alarms to enable actions for + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_EnableAlarmActions.html + # + + def enable_alarm_actions(alarm_names) + options = {} + options.merge!(Aws.indexed_param('AlarmNames.member.%d', [*alarm_names])) + request({ + 'Action' => 'EnableAlarmActions', + :parser => Fog::Parsers::AWS::CloudWatch::EnableAlarmActions.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/get_metric_statistics.rb b/lib/fog/aws/requests/cloud_watch/get_metric_statistics.rb new file mode 100644 index 000000000..3ec18f2f2 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/get_metric_statistics.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/get_metric_statistics' + + # Fetch datapoints for a metric. At most 1440 datapoints will be returned, the most datapoints that can be queried is 50850 + # StartTime is capped to 2 weeks ago + # ==== Options + # * Namespace<~String>: the namespace of the metric + # * MetricName<~String>: the name of the metric + # * StartTime<~Datetime>: when to start fetching datapoints from (inclusive) + # * EndTime<~Datetime>: used to determine the last datapoint to fetch (exclusive) + # * Period<~Integer>: Granularity, in seconds of the returned datapoints. Must be a multiple of 60, and at least 60 + # * Statistics<~Array>: An array of up to 5 strings, which name the statistics to return + # * Unit<~String>: The unit for the metric + # * Dimensions<~Array>: a list of dimensions to filter against (optional) + # Name : The name of the dimension + # Value : The value to filter against + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html + # + def get_metric_statistics(options={}) + %w{Statistics StartTime EndTime Period MetricName Namespace}.each do |required_parameter| + raise ArgumentError, "Must provide #{required_parameter}" unless options.key?(required_parameter) + end + statistics = options.delete 'Statistics' + options.merge!(Aws.indexed_param('Statistics.member.%d', [*statistics])) + + if dimensions = options.delete('Dimensions') + options.merge!(Aws.indexed_param('Dimensions.member.%d.Name', dimensions.map {|dimension| dimension['Name']})) + options.merge!(Aws.indexed_param('Dimensions.member.%d.Value', dimensions.map {|dimension| dimension['Value']})) + end + + request({ + 'Action' => 'GetMetricStatistics', + :parser => Fog::Parsers::AWS::CloudWatch::GetMetricStatistics.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/list_metrics.rb b/lib/fog/aws/requests/cloud_watch/list_metrics.rb new file mode 100644 index 000000000..4c448dd6b --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/list_metrics.rb @@ -0,0 +1,62 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/list_metrics' + + # List availabe metrics + # + # ==== Options + # * Dimensions<~Array>: a list of dimensions to filter against, + # Name : The name of the dimension + # Value : The value to filter against + # * MetricName<~String>: The name of the metric to filter against + # * Namespace<~String>: The namespace to filter against + # * NextToken<~String> The token returned by a previous call to indicate that there is more data available + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html + # + def list_metrics(options={}) + if dimensions = options.delete('Dimensions') + options.merge!(Aws.indexed_param('Dimensions.member.%d.Name', dimensions.map {|dimension| dimension['Name']})) + options.merge!(Aws.indexed_param('Dimensions.member.%d.Value', dimensions.map {|dimension| dimension['Value']})) + end + + request({ + 'Action' => 'ListMetrics', + :parser => Fog::Parsers::AWS::CloudWatch::ListMetrics.new + }.merge(options)) + end + end + + class Mock + def list_metrics(options={}) + body = case options["NextToken"] + when nil + { "ListMetricsResult" => { + "Metrics" => (0...500).map{ {} }, + "NextToken" => '1' + }} + when "1" + { "ListMetricsResult" => { + "Metrics" => (0...500).map{ {} }, + "NextToken" => '2' + }} + when "2" + { "ListMetricsResult" => { + "Metrics" => (0...1).map{ {} } + }} + end + + Excon::Response.new.tap do |response| + response.body = body + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/put_metric_alarm.rb b/lib/fog/aws/requests/cloud_watch/put_metric_alarm.rb new file mode 100644 index 000000000..2f20e9cb3 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/put_metric_alarm.rb @@ -0,0 +1,93 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/put_metric_alarm' + + # Creates or updates an alarm and associates it with the specified Amazon CloudWatch metric + # ==== Options + # * ActionsEnabled<~Boolean>: Indicates whether or not actions should be executed during any changes to the alarm's state + # * AlarmActions<~Array>: A list of actions to execute + # * AlarmDescription<~String>: The description for the alarm + # * AlarmName<~String> The unique name for the alarm + # * ComparisonOperator<~String>: The arithmetic operation to use for comparison + # * Dimensions<~Array>: a list of dimensions to filter against, + # Name : The name of the dimension + # Value : The value to filter against + # * EvaluationPeriods<~Integer>: The number of periods over which data is compared to the specified threshold + # * InsufficientDataActions<~Array>: A list of actions to execute + # * MetricName<~String>: The name for the alarm's associated metric + # * Namespace<~String>: The namespace for the alarm's associated metric + # * OKActions<~Array>: A list of actions to execute + # * Period<~Integer>: The period in seconds over which the specified statistic is applied + # * Statistic<~String>: The statistic to apply to the alarm's associated metric + # * Threshold<~Double>: The value against which the specified statistic is compared + # * Unit<~String>: The unit for the alarm's associated metric + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_PutMetricAlarm.html + # + def put_metric_alarm(options) + if dimensions = options.delete('Dimensions') + options.merge!(Aws.indexed_param('Dimensions.member.%d.Name', dimensions.map {|dimension| dimension['Name']})) + options.merge!(Aws.indexed_param('Dimensions.member.%d.Value', dimensions.map {|dimension| dimension['Value']})) + end + if alarm_actions = options.delete('AlarmActions') + options.merge!(Aws.indexed_param('AlarmActions.member.%d', [*alarm_actions])) + end + if insufficient_data_actions = options.delete('InsufficientDataActions') + options.merge!(Aws.indexed_param('InsufficientDataActions.member.%d', [*insufficient_data_actions])) + end + if ok_actions = options.delete('OKActions') + options.merge!(Aws.indexed_param('OKActions.member.%d', [*ok_actions])) + end + + request({ + 'Action' => 'PutMetricAlarm', + :parser => Fog::Parsers::AWS::CloudWatch::PutMetricAlarm.new + }.merge(options)) + end + end + + class Mock + require 'fog/aws/parsers/cloud_watch/put_metric_alarm' + + # See: Fog::AWS::CloudWatch::Real.put_metric_alarm() + # + def put_metric_alarm(options) + supported_actions = [ "InsufficientDataActions", "OKActions", "AlarmActions" ] + found_actions = options.keys.select {|key| supported_actions.include? key } + if found_actions.empty? + raise Fog::Compute::AWS::Error.new("The request must contain at least one of #{supported_actions.join(", ")}'") + end + + requirements = [ "AlarmName", "ComparisonOperator", "EvaluationPeriods", "Namespace", "Period", "Statistic", "Threshold" ] + requirements.each do |req| + unless options.key?(req) + raise Fog::Compute::AWS::Error.new("The request must contain a the parameter '%s'" % req) + end + end + + data[:metric_alarms][options['AlarmName']] = { + 'AlarmARN' => "arn:aws:cloudwatch:eu-west-1:000000000000:metricAlarm:00000000-0000-0000-0000-000000000000:alarmName/#{options['AlarmName']}", + 'ActionsEnabled' => false, + 'AlarmActions' => [], + 'AlarmConfigurationUpdatedTimestamp' => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"), + 'Dimensions' => [], + 'OKActions' => [], + }.merge!(options) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/put_metric_data.rb b/lib/fog/aws/requests/cloud_watch/put_metric_data.rb new file mode 100644 index 000000000..746e81986 --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/put_metric_data.rb @@ -0,0 +1,72 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/put_metric_data' + + # Publishes one or more data points to CloudWatch. A new metric is created if necessary + # ==== Options + # * Namespace<~String>: the namespace of the metric data + # * MetricData<~Array>: the datapoints to publish of the metric + # * MetricName<~String>: the name of the metric + # * Timestamp<~String>: the timestamp for the data point. If omitted defaults to the time at which the data is received by CloudWatch + # * Unit<~String>: the unit + # * Value<~Double> the value for the metric + # * StatisticValues<~Hash>: + # * Maximum<~Double>: the maximum value of the sample set + # * Sum<~Double>: the sum of the values of the sample set + # * SampleCount<~Double>: the number of samples used for the statistic set + # * Minimum<~Double>: the minimum value of the sample set + # * Dimensions<~Array>: the dimensions for the metric. From 0 to 10 may be included + # * Name<~String> + # * Value<~String> + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html + # + + def put_metric_data(namespace, metric_data) + options = {'Namespace' => namespace} + + #first index the dimensions for any of the datums that have dimensions + metric_data.map! do |metric_datum| + if dimensions = metric_datum.delete('Dimensions') + metric_datum.merge!(Aws.indexed_param('Dimensions.member.%d.Name', dimensions.map {|dimension| dimension['Name']})) + metric_datum.merge!(Aws.indexed_param('Dimensions.member.%d.Value', dimensions.map {|dimension| dimension['Value']})) + end + metric_datum + end + #then flatten out an hashes in the metric_data array + metric_data.map! { |metric_datum| flatten_hash(metric_datum) } + #then index the metric_data array + options.merge!(Aws.indexed_param('MetricData.member.%d', [*metric_data])) + #then finally flatten out an hashes in the overall options array + options = flatten_hash(options) + + request({ + 'Action' => 'PutMetricData', + :parser => Fog::Parsers::AWS::CloudWatch::PutMetricData.new + }.merge(options)) + end + private + + def flatten_hash(starting) + finishing = {} + starting.each do |top_level_key, top_level_value| + if top_level_value.is_a?(Hash) + nested_hash = top_level_value + nested_hash.each do |nested_key, nested_value| + finishing["#{top_level_key}.#{nested_key}"] = nested_value + end + else + finishing[top_level_key] = top_level_value + end + end + return finishing + end + end + end + end +end diff --git a/lib/fog/aws/requests/cloud_watch/set_alarm_state.rb b/lib/fog/aws/requests/cloud_watch/set_alarm_state.rb new file mode 100644 index 000000000..f16d8769b --- /dev/null +++ b/lib/fog/aws/requests/cloud_watch/set_alarm_state.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class CloudWatch + class Real + require 'fog/aws/parsers/cloud_watch/set_alarm_state' + + # Temporarily sets the state of an alarm + # ==== Options + # * AlarmName<~String>: The names of the alarm + # * StateReason<~String>: The reason that this alarm is set to this specific state (in human-readable text format) + # * StateReasonData<~String>: The reason that this alarm is set to this specific state (in machine-readable JSON format) + # * StateValue<~String>: The value of the state + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_SetAlarmState.html + # + + def set_alarm_state(options) + request({ + 'Action' => 'SetAlarmState', + :parser => Fog::Parsers::AWS::CloudWatch::SetAlarmState.new + }.merge(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/allocate_address.rb b/lib/fog/aws/requests/compute/allocate_address.rb new file mode 100644 index 000000000..2a3a9e025 --- /dev/null +++ b/lib/fog/aws/requests/compute/allocate_address.rb @@ -0,0 +1,55 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/allocate_address' + + # Acquire an elastic IP address. + # + # ==== Parameters + # * domain<~String> - Type of EIP, either standard or vpc + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'publicIp'<~String> - The acquired address + # * 'requestId'<~String> - Id of the request + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-AllocateAddress.html] + def allocate_address(domain='standard') + domain = domain == 'vpc' ? 'vpc' : 'standard' + request( + 'Action' => 'AllocateAddress', + 'Domain' => domain, + :parser => Fog::Parsers::Compute::AWS::AllocateAddress.new + ) + end + end + + class Mock + def allocate_address(domain = 'standard') + domain = domain == 'vpc' ? 'vpc' : 'standard' + response = Excon::Response.new + if describe_addresses.body['addressesSet'].size < self.data[:limits][:addresses] + response.status = 200 + public_ip = Fog::AWS::Mock.ip_address + data = { + 'instanceId' => nil, + 'publicIp' => public_ip, + 'domain' => domain + } + if domain == 'vpc' + data['allocationId'] = "eipalloc-#{Fog::Mock.random_hex(8)}" + end + self.data[:addresses][public_ip] = data + response.body = data.reject {|k, v| k == 'instanceId' }.merge('requestId' => Fog::AWS::Mock.request_id) + response + else + response.status = 400 + response.body = "AddressLimitExceededToo many addresses allocated#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/assign_private_ip_addresses.rb b/lib/fog/aws/requests/compute/assign_private_ip_addresses.rb new file mode 100644 index 000000000..a1bf2138a --- /dev/null +++ b/lib/fog/aws/requests/compute/assign_private_ip_addresses.rb @@ -0,0 +1,55 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/assign_private_ip_addresses' + + # Assigns one or more secondary private IP addresses to the specified network interface. + # + # ==== Parameters + # * NetworkInterfaceId<~String> - The ID of the network interface + # * PrivateIpAddresses<~Array> - One or more IP addresses to be assigned as a secondary private IP address (conditional) + # * SecondaryPrivateIpAddressCount<~String> - The number of secondary IP addresses to assign (conditional) + # * AllowReassignment<~Boolean> - Whether to reassign an IP address + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - The ID of the request. + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-AssignPrivateIpAddresses.html] + def assign_private_ip_addresses(network_interface_id, options={}) + if options['PrivateIpAddresses'] && options['SecondaryPrivateIpAddressCount'] + raise Fog::Compute::AWS::Error.new("You may specify secondaryPrivateIpAddressCount or specific secondary private IP addresses, but not both.") + end + + if private_ip_addresses = options.delete('PrivateIpAddresses') + options.merge!(Fog::AWS.indexed_param('PrivateIpAddress.%d', [*private_ip_addresses])) + end + + request({ + 'Action' => 'AssignPrivateIpAddresses', + 'NetworkInterfaceId' => network_interface_id, + :parser => Fog::Parsers::Compute::AWS::AssignPrivateIpAddresses.new + }.merge(options)) + end + end + + class Mock + def assign_private_ip_addresses(network_interface_id, options={}) + if options['PrivateIpAddresses'] && options['SecondaryPrivateIpAddressCount'] + raise Fog::Compute::AWS::Error.new("You may specify secondaryPrivateIpAddressCount or specific secondary private IP addresses, but not both.") + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/associate_address.rb b/lib/fog/aws/requests/compute/associate_address.rb new file mode 100644 index 000000000..a9d32179f --- /dev/null +++ b/lib/fog/aws/requests/compute/associate_address.rb @@ -0,0 +1,126 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/associate_address' + + # Associate an elastic IP address with an instance + # + # ==== Parameters + # * instance_id<~String> - Id of instance to associate address with (conditional) + # * public_ip<~String> - Public ip to assign to instance (conditional) + # * network_interface_id<~String> - Id of a nic to associate address with (required in a vpc instance with more than one nic) (conditional) + # * allocation_id<~String> - Allocation Id to associate address with (vpc only) (conditional) + # * private_ip_address<~String> - Private Ip Address to associate address with (vpc only) + # * allow_reassociation<~Boolean> - Allows an elastic ip address to be reassigned (vpc only) (conditional) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # * 'associationId'<~String> - association Id for eip to node (vpc only) + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-AssociateAddress.html] + def associate_address(*args) + if args.first.kind_of? Hash + params = args.first + else + params = { + :instance_id => args[0], + :public_ip => args[1], + :network_interface_id => args[2], + :allocation_id => args[3], + :private_ip_address => args[4], + :allow_reassociation => args[5], + } + end + # Cannot specify an allocation ip and a public IP at the same time. If you have an allocation Id presumably you are in a VPC + # so we will null out the public IP + params[:public_ip] = params[:allocation_id].nil? ? params[:public_ip] : nil + + request( + 'Action' => 'AssociateAddress', + 'AllocationId' => params[:allocation_id], + 'InstanceId' => params[:instance_id], + 'NetworkInterfaceId' => params[:network_interface_id], + 'PublicIp' => params[:public_ip], + 'PrivateIpAddress' => params[:private_ip_address], + 'AllowReassociation' => params[:allow_reassociation], + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::AssociateAddress.new + ) + end + end + + class Mock + def associate_address(*args) + if args.first.kind_of? Hash + params = args.first + else + params = { + :instance_id => args[0], + :public_ip => args[1], + :network_interface_id => args[2], + :allocation_id => args[3], + :private_ip_address => args[4], + :allow_reassociation => args[5], + } + end + params[:public_ip] = params[:allocation_id].nil? ? params[:public_ip] : nil + response = Excon::Response.new + response.status = 200 + instance = self.data[:instances][params[:instance_id]] + # address = self.data[:addresses][params[:public_ip]] + address = params[:public_ip].nil? ? nil : self.data[:addresses][params[:public_ip]] + # This is a classic server, a VPC with a single network interface id or a VPC with multiple network interfaces one of which is specified + if ((instance && address) || (instance && !params[:allocation_id].nil?) || (!params[:allocation_id].nil? && !network_interface_id.nil?)) + if !params[:allocation_id].nil? + allocation_ip = describe_addresses( 'allocation-id' => "#{params[:allocation_id]}").body['addressesSet'].first + if !allocation_ip.nil? + public_ip = allocation_ip['publicIp'] + address = public_ip.nil? ? nil : self.data[:addresses][public_ip] + end + end + if !address.nil? + if current_instance = self.data[:instances][address['instanceId']] + current_instance['ipAddress'] = current_instance['originalIpAddress'] + end + address['instanceId'] = params[:instance_id] + end + # detach other address (if any) + if self.data[:addresses][instance['ipAddress']] + self.data[:addresses][instance['ipAddress']]['instanceId'] = nil + end + if !params[:public_ip].nil? + instance['ipAddress'] = params[:public_ip] + instance['dnsName'] = Fog::AWS::Mock.dns_name_for(params[:public_ip]) + end + response.status = 200 + if !params[:instance_id].nil? && !params[:public_ip].nil? + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + elsif !params[:allocation_id].nil? + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true, + 'associationId' => Fog::AWS::Mock.request_id + } + end + response + elsif !instance + raise Fog::Compute::AWS::NotFound.new("You must specify either an InstanceId or a NetworkInterfaceID") + elsif !address + raise Fog::Compute::AWS::Error.new("AuthFailure => The address '#{public_ip}' does not belong to you.") + elsif params[:network_interface_id].nil? && params[:allocation_id].nil? + raise Fog::Compute::AWS::NotFound.new("You must specify an AllocationId when specifying a NetworkInterfaceID") + else (!instance.nil? && params[:network_interface_id].nil?) || (params[:instance_id].nil? && !params[:network_interface_id].nil?) + raise Fog::Compute::AWS::Error.new("You must specify either an InstanceId or a NetworkInterfaceID") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/associate_dhcp_options.rb b/lib/fog/aws/requests/compute/associate_dhcp_options.rb new file mode 100644 index 000000000..d80892e75 --- /dev/null +++ b/lib/fog/aws/requests/compute/associate_dhcp_options.rb @@ -0,0 +1,53 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + # + # + # ==== Parameters + # * dhcp_options_id<~String> - The ID of the DHCP options you want to associate with the VPC, or "default" if you want the VPC + # to use no DHCP options. + # * vpc_id<~String> - The ID of the VPC + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-AssociateDhcpOptions.html] + def associate_dhcp_options(dhcp_options_id, vpc_id) + request( + 'Action' => 'AssociateDhcpOptions', + 'DhcpOptionsId' => dhcp_options_id, + 'VpcId' => vpc_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def associate_dhcp_options(dhcp_options_id, vpc_id) + response = Excon::Response.new + if dhcp_options_id && vpc_id + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + if !dhcp_options_id + message << 'The request must contain the parameter dhcp_options_id' + elsif !vpc_id + message << 'The request must contain the parameter vpc_id' + end + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/associate_route_table.rb b/lib/fog/aws/requests/compute/associate_route_table.rb new file mode 100755 index 000000000..b1dd6b89c --- /dev/null +++ b/lib/fog/aws/requests/compute/associate_route_table.rb @@ -0,0 +1,70 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/associate_route_table' + # Associates a subnet with a route table. + # + # ==== Parameters + # * RouteTableId<~String> - The ID of the route table + # * SubnetId<~String> - The ID of the subnet + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - The ID of the request + # * 'associationId'<~String> - The route table association ID (needed to disassociate the route table) + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-AssociateRouteTable.html] + def associate_route_table(routeTableId, subnetId) + request( + 'Action' => 'AssociateRouteTable', + 'RouteTableId' => routeTableId, + 'SubnetId' => subnetId, + :parser => Fog::Parsers::Compute::AWS::AssociateRouteTable.new + ) + end + end + + class Mock + def associate_route_table(routeTableId, subnetId) + routetable = self.data[:route_tables].find { |routetable| routetable["routeTableId"].eql? routeTableId } + subnet = self.data[:subnets].find { |subnet| subnet["subnetId"].eql? subnetId } + + if !routetable.nil? && !subnet.nil? + response = Excon::Response.new + response.status = 200 + association = add_route_association(routeTableId, subnetId) + routetable["associationSet"].push(association) + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'associationId' => association['routeTableAssociationId'] + } + response + elsif routetable.nil? + raise Fog::Compute::AWS::NotFound.new("The routeTable ID '#{routeTableId}' does not exist") + else + raise Fog::Compute::AWS::NotFound.new("The subnet ID '#{subnetId}' does not exist") + end + end + + private + + def add_route_association(routeTableId, subnetId, main=nil) + response = { + "routeTableAssociationId" => "rtbassoc-#{Fog::Mock.random_hex(8)}", + "routeTableId" => routeTableId, + "subnetId" => nil, + "main" => false + } + if main + response['main'] = true + else + response['subnetId'] = subnetId + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/attach_internet_gateway.rb b/lib/fog/aws/requests/compute/attach_internet_gateway.rb new file mode 100644 index 000000000..9416937ed --- /dev/null +++ b/lib/fog/aws/requests/compute/attach_internet_gateway.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + # Attaches an Internet gateway to a VPC, enabling connectivity between the Internet and the VPC + # + # ==== Parameters + # * internet_gateway_id<~String> - The ID of the Internet gateway to attach + # * vpc_id<~String> - The ID of the VPC + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-AttachInternetGateway.html] + def attach_internet_gateway(internet_gateway_id, vpc_id) + request( + 'Action' => 'AttachInternetGateway', + 'InternetGatewayId' => internet_gateway_id, + 'VpcId' => vpc_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def attach_internet_gateway(internet_gateway_id, vpc_id) + response = Excon::Response.new + if internet_gateway_id && vpc_id + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + if !internet_gateway_id + message << 'The request must contain the parameter internet_gateway_id' + elsif !vpc_id + message << 'The request must contain the parameter vpc_id' + end + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/attach_network_interface.rb b/lib/fog/aws/requests/compute/attach_network_interface.rb new file mode 100644 index 000000000..8b5887396 --- /dev/null +++ b/lib/fog/aws/requests/compute/attach_network_interface.rb @@ -0,0 +1,61 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/attach_network_interface' + + # Attach a network interface + # + # ==== Parameters + # * networkInterfaceId<~String> - ID of the network interface to attach + # * instanceId<~String> - ID of the instance that will be attached to the network interface + # * deviceIndex<~Integer> - index of the device for the network interface attachment on the instance + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'attachmentId'<~String> - ID of the attachment + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/index.html?ApiReference-query-AttachNetworkInterface.html] + def attach_network_interface(nic_id, instance_id, device_index) + request( + 'Action' => 'AttachNetworkInterface', + 'NetworkInterfaceId' => nic_id, + 'InstanceId' => instance_id, + 'DeviceIndex' => device_index, + :parser => Fog::Parsers::Compute::AWS::AttachNetworkInterface.new + ) + end + end + + class Mock + def attach_network_interface(nic_id, instance_id, device_index) + response = Excon::Response.new + if ! self.data[:instances].find{ |i,i_conf| + i_conf['instanceId'] == instance_id + } + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_id}' does not exist") + elsif self.data[:network_interfaces].find{ |ni,ni_conf| ni_conf['attachment']['instanceId'] == instance_id && ni_conf['attachment']['deviceIndex'] == device_index } + raise Fog::Compute::AWS::Error.new("InvalidParameterValue => Instance '#{instance_id}' already has an interface attached at device index '#{device_index}'.") + elsif self.data[:network_interfaces][nic_id] + attachment = self.data[:network_interfaces][nic_id]['attachment'] + attachment['attachmentId'] = Fog::AWS::Mock.request_id + attachment['instanceId'] = instance_id + attachment['deviceIndex'] = device_index + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'attachmentId' => attachment['attachmentId'] + } + else + raise Fog::Compute::AWS::NotFound.new("The network interface '#{nic_id}' does not exist") + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/attach_volume.rb b/lib/fog/aws/requests/compute/attach_volume.rb new file mode 100644 index 000000000..a3db7d9e5 --- /dev/null +++ b/lib/fog/aws/requests/compute/attach_volume.rb @@ -0,0 +1,83 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/attach_volume' + + # Attach an Amazon EBS volume with a running instance, exposing as specified device + # + # ==== Parameters + # * instance_id<~String> - Id of instance to associate volume with + # * volume_id<~String> - Id of amazon EBS volume to associate with instance + # * device<~String> - Specifies how the device is exposed to the instance (e.g. "/dev/sdh") + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'attachTime'<~Time> - Time of attachment was initiated at + # * 'device'<~String> - Device as it is exposed to the instance + # * 'instanceId'<~String> - Id of instance for volume + # * 'requestId'<~String> - Id of request + # * 'status'<~String> - Status of volume + # * 'volumeId'<~String> - Reference to volume + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-AttachVolume.html] + def attach_volume(instance_id, volume_id, device) + request( + 'Action' => 'AttachVolume', + 'VolumeId' => volume_id, + 'InstanceId' => instance_id, + 'Device' => device, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::AttachVolume.new + ) + end + end + + class Mock + def attach_volume(instance_id, volume_id, device) + response = Excon::Response.new + if instance_id && volume_id && device + response.status = 200 + instance = self.data[:instances][instance_id] + volume = self.data[:volumes][volume_id] + if instance && volume + unless volume['status'] == 'available' + raise Fog::Compute::AWS::Error.new("Client.VolumeInUse => Volume #{volume_id} is unavailable") + end + + data = { + 'attachTime' => Time.now, + 'device' => device, + 'instanceId' => instance_id, + 'status' => 'attaching', + 'volumeId' => volume_id + } + volume['attachmentSet'] = [data] + volume['status'] = 'attaching' + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + response + elsif !instance + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_id}' does not exist.") + elsif !volume + raise Fog::Compute::AWS::NotFound.new("The volume '#{volume_id}' does not exist.") + end + else + message = 'MissingParameter => ' + if !instance_id + message << 'The request must contain the parameter instance_id' + elsif !volume_id + message << 'The request must contain the parameter volume_id' + else + message << 'The request must contain the parameter device' + end + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/authorize_security_group_ingress.rb b/lib/fog/aws/requests/compute/authorize_security_group_ingress.rb new file mode 100644 index 000000000..0c721d41e --- /dev/null +++ b/lib/fog/aws/requests/compute/authorize_security_group_ingress.rb @@ -0,0 +1,230 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Add permissions to a security group + # + # ==== Parameters + # * group_name<~String> - Name of group, optional (can also be specifed as GroupName in options) + # * options<~Hash>: + # * 'GroupName'<~String> - Name of security group to modify + # * 'GroupId'<~String> - Id of security group to modify + # * 'SourceSecurityGroupName'<~String> - Name of security group to authorize + # * 'SourceSecurityGroupOwnerId'<~String> - Name of owner to authorize + # or + # * 'CidrIp'<~String> - CIDR range + # * 'FromPort'<~Integer> - Start of port range (or -1 for ICMP wildcard) + # * 'IpProtocol'<~String> - Ip protocol, must be in ['tcp', 'udp', 'icmp'] + # * 'ToPort'<~Integer> - End of port range (or -1 for ICMP wildcard) + # or + # * 'IpPermissions'<~Array>: + # * permission<~Hash>: + # * 'FromPort'<~Integer> - Start of port range (or -1 for ICMP wildcard) + # * 'Groups'<~Array>: + # * group<~Hash>: + # * 'GroupName'<~String> - Name of security group to authorize + # * 'UserId'<~String> - Name of owner to authorize + # * 'IpProtocol'<~String> - Ip protocol, must be in ['tcp', 'udp', 'icmp'] + # * 'IpRanges'<~Array>: + # * ip_range<~Hash>: + # * 'CidrIp'<~String> - CIDR range + # * 'ToPort'<~Integer> - End of port range (or -1 for ICMP wildcard) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-AuthorizeSecurityGroupIngress.html] + def authorize_security_group_ingress(group_name, options = {}) + options = Fog::AWS.parse_security_group_options(group_name, options) + + if ip_permissions = options.delete('IpPermissions') + options.merge!(indexed_ip_permissions_params(ip_permissions)) + end + + request({ + 'Action' => 'AuthorizeSecurityGroupIngress', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(options)) + end + + private + + def indexed_ip_permissions_params(ip_permissions) + params = {} + ip_permissions.each_with_index do |permission, key_index| + key_index += 1 + params[format('IpPermissions.%d.IpProtocol', key_index)] = permission['IpProtocol'] + params[format('IpPermissions.%d.FromPort', key_index)] = permission['FromPort'] + params[format('IpPermissions.%d.ToPort', key_index)] = permission['ToPort'] + (permission['Groups'] || []).each_with_index do |group, group_index| + group_index += 1 + params[format('IpPermissions.%d.Groups.%d.UserId', key_index, group_index)] = group['UserId'] + params[format('IpPermissions.%d.Groups.%d.GroupName', key_index, group_index)] = group['GroupName'] + params[format('IpPermissions.%d.Groups.%d.GroupId', key_index, group_index)] = group['GroupId'] + end + (permission['IpRanges'] || []).each_with_index do |ip_range, range_index| + range_index += 1 + params[format('IpPermissions.%d.IpRanges.%d.CidrIp', key_index, range_index)] = ip_range['CidrIp'] + end + end + params.reject {|k, v| v.nil? } + end + end + + class Mock + def authorize_security_group_ingress(group_name, options = {}) + options = Fog::AWS.parse_security_group_options(group_name, options) + if options.key?('GroupName') + group_name = options['GroupName'] + else + group_name = self.data[:security_groups].reject { |k,v| v['groupId'] != options['GroupId'] } .keys.first + end + + response = Excon::Response.new + group = self.data[:security_groups][group_name] + + if group + verify_permission_options(options, group['vpcId'] != nil) + + normalized_permissions = normalize_permissions(options) + + normalized_permissions.each do |permission| + if matching_group_permission = find_matching_permission(group, permission) + if permission['groups'].any? {|pg| matching_group_permission['groups'].include?(pg) } + raise Fog::Compute::AWS::Error, "InvalidPermission.Duplicate => The permission '123' has already been authorized in the specified group" + end + + if permission['ipRanges'].any? {|pr| matching_group_permission['ipRanges'].include?(pr) } + raise Fog::Compute::AWS::Error, "InvalidPermission.Duplicate => The permission '123' has already been authorized in the specified group" + end + end + end + + normalized_permissions.each do |permission| + if matching_group_permission = find_matching_permission(group, permission) + matching_group_permission['groups'] += permission['groups'] + matching_group_permission['ipRanges'] += permission['ipRanges'] + else + group['ipPermissions'] << permission + end + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The security group '#{group_name}' does not exist") + end + end + + private + + def verify_permission_options(options, is_vpc) + if options.size <= 1 + raise Fog::Compute::AWS::Error.new("InvalidRequest => The request received was invalid.") + end + if !is_vpc && options['IpProtocol'] && !['tcp', 'udp', 'icmp'].include?(options['IpProtocol']) + raise Fog::Compute::AWS::Error.new("InvalidPermission.Malformed => Unsupported IP protocol \"#{options['IpProtocol']}\" - supported: [tcp, udp, icmp]") + end + if !is_vpc && (options['IpProtocol'] && (!options['FromPort'] || !options['ToPort'])) + raise Fog::Compute::AWS::Error.new("InvalidPermission.Malformed => TCP/UDP port (-1) out of range") + end + if options.key?('IpPermissions') + if !options['IpPermissions'].is_a?(Array) || options['IpPermissions'].empty? + raise Fog::Compute::AWS::Error.new("InvalidRequest => The request received was invalid.") + end + options['IpPermissions'].each {|p| verify_permission_options(p, is_vpc) } + end + end + + def normalize_permissions(options) + normalized_permissions = [] + if options['SourceSecurityGroupName'] + group_name = if options['SourceSecurityGroupName'] =~ /default_elb/ + "default" + else + options['SourceSecurityGroupName'] + end + source_group_id=self.data[:security_groups][group_name]['groupId'] + ['tcp', 'udp'].each do |protocol| + normalized_permissions << { + 'ipProtocol' => protocol, + 'fromPort' => 1, + 'toPort' => 65535, + 'groups' => [{'groupName' => options['SourceSecurityGroupName'], 'userId' => options['SourceSecurityGroupOwnerId'] || self.data[:owner_id], 'groupId' => source_group_id }], + 'ipRanges' => [] + } + end + normalized_permissions << { + 'ipProtocol' => 'icmp', + 'fromPort' => -1, + 'toPort' => -1, + 'groups' => [{'groupName' => options['SourceSecurityGroupName'], 'userId' => options['SourceSecurityGroupOwnerId'] || self.data[:owner_id], 'groupId' => source_group_id }], + 'ipRanges' => [] + } + elsif options['CidrIp'] + normalized_permissions << { + 'ipProtocol' => options['IpProtocol'], + 'fromPort' => Integer(options['FromPort']), + 'toPort' => Integer(options['ToPort']), + 'groups' => [], + 'ipRanges' => [{'cidrIp' => options['CidrIp']}] + } + elsif options['IpPermissions'] + options['IpPermissions'].each do |permission| + if ['tcp', 'udp', 'icmp'].include?(permission['IpProtocol']) + normalized_permissions << { + 'ipProtocol' => permission['IpProtocol'], + 'fromPort' => Integer(permission['FromPort']), + 'toPort' => Integer(permission['ToPort']), + 'groups' => (permission['Groups'] || []).map do |authorized_group| + security_group = if group_name = authorized_group['GroupName'] + self.data[:security_groups][group_name] || {} + elsif group_id = authorized_group['GroupId'] + self.data[:security_groups].values.find { |sg| sg['groupId'] == group_id } || {} + end + + {'groupName' => authorized_group['GroupName'] || security_group["groupName"], 'userId' => authorized_group['UserId'] || self.data[:owner_id], 'groupId' => authorized_group["GroupId"] || security_group['groupId']} + end, + 'ipRanges' => (permission['IpRanges'] || []).map {|r| { 'cidrIp' => r['CidrIp'] } } + } + else + normalized_permissions << { + 'ipProtocol' => permission['IpProtocol'], + 'groups' => (permission['Groups'] || []).map do |authorized_group| + security_group = if group_name = authorized_group['GroupName'] + self.data[:security_groups][group_name] || {} + elsif group_id = authorized_group['GroupId'] + self.data[:security_groups].values.find { |sg| sg['groupId'] == group_id } || {} + end + + {'groupName' => authorized_group['GroupName'] || security_group["groupName"], 'userId' => authorized_group['UserId'] || self.data[:owner_id], 'groupId' => authorized_group["GroupId"] || security_group['groupId']} + end, + 'ipRanges' => (permission['IpRanges'] || []).map {|r| { 'cidrIp' => r['CidrIp'] } } + } + end + end + end + + normalized_permissions + end + + def find_matching_permission(group, permission) + group['ipPermissions'].find {|group_permission| + permission['ipProtocol'] == group_permission['ipProtocol'] && + permission['fromPort'] == group_permission['fromPort'] && + permission['toPort'] == group_permission['toPort'] } + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb b/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb new file mode 100644 index 000000000..8219fbd0a --- /dev/null +++ b/lib/fog/aws/requests/compute/cancel_spot_instance_requests.rb @@ -0,0 +1,32 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/cancel_spot_instance_requests' + + # Terminate specified spot instance requests + # + # ==== Parameters + # * spot_instance_request_id<~Array> - Ids of instances to terminates + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> id of request + # * 'spotInstanceRequestSet'<~Array>: + # * 'spotInstanceRequestId'<~String> - id of cancelled spot instance + # * 'state'<~String> - state of cancelled spot instance + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CancelSpotInstanceRequests.html] + def cancel_spot_instance_requests(spot_instance_request_id) + params = Fog::AWS.indexed_param('SpotInstanceRequestId', spot_instance_request_id) + request({ + 'Action' => 'CancelSpotInstanceRequests', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::CancelSpotInstanceRequests.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/copy_image.rb b/lib/fog/aws/requests/compute/copy_image.rb new file mode 100644 index 000000000..8b4ee9d35 --- /dev/null +++ b/lib/fog/aws/requests/compute/copy_image.rb @@ -0,0 +1,59 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/copy_image' + + # Copy an image to a different region + # + # ==== Parameters + # * source_image_id<~String> - The ID of the AMI to copy + # * source_region<~String> - The name of the Aws region that contains the AMI to be copied + # * name<~String> - The name of the new AMI in the destination region + # * description<~String> - The description to set on the new AMI in the destination region + # * client_token<~String> - Unique, case-sensitive identifier you provide to ensure idempotency of the request + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - id of request + # * 'imageId'<~String> - id of image + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/CommandLineReference/ApiReference-cmd-CopyImage.html] + def copy_image(source_image_id, source_region, name = nil, description = nil, client_token = nil) + request( + 'Action' => 'CopyImage', + 'SourceImageId' => source_image_id, + 'SourceRegion' => source_region, + 'Name' => name, + 'Description' => description, + 'ClientToken' => client_token, + :parser => Fog::Parsers::Compute::AWS::CopyImage.new + ) + end + end + + class Mock + # + # Usage + # + # Aws[:compute].copy_image("ami-1aad5273", 'us-east-1') + # + + def copy_image(source_image_id, source_region, name = nil, description = nil, client_token = nil) + response = Excon::Response.new + response.status = 200 + image_id = Fog::AWS::Mock.image_id + data = { + 'imageId' => image_id, + } + self.data[:images][image_id] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/copy_snapshot.rb b/lib/fog/aws/requests/compute/copy_snapshot.rb new file mode 100644 index 000000000..22fda1de1 --- /dev/null +++ b/lib/fog/aws/requests/compute/copy_snapshot.rb @@ -0,0 +1,54 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/copy_snapshot' + + # Copy a snapshot to a different region + # + # ==== Parameters + # * source_snapshot_id<~String> - Id of snapshot + # * source_region<~String> - Region to move it from + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - id of request + # * 'snapshotId'<~String> - id of snapshot + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CopySnapshot.html] + def copy_snapshot(source_snapshot_id, source_region, description = nil) + request( + 'Action' => 'CopySnapshot', + 'SourceSnapshotId'=> source_snapshot_id, + 'SourceRegion' => source_region, + 'Description' => description, + :parser => Fog::Parsers::Compute::AWS::CopySnapshot.new + ) + end + end + + class Mock + # + # Usage + # + # Aws[:compute].copy_snapshot("snap-1db0a957", 'us-east-1') + # + + def copy_snapshot(source_snapshot_id, source_region, description = nil) + response = Excon::Response.new + response.status = 200 + snapshot_id = Fog::AWS::Mock.snapshot_id + data = { + 'snapshotId' => snapshot_id, + } + self.data[:snapshots][snapshot_id] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_dhcp_options.rb b/lib/fog/aws/requests/compute/create_dhcp_options.rb new file mode 100644 index 000000000..0c9bdac37 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_dhcp_options.rb @@ -0,0 +1,74 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_dhcp_options' + + # Creates a set of DHCP options for your VPC + # + # ==== Parameters + # * DhcpConfigurationOptions<~Hash> - hash of key value dhcp options to assign + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateDhcpOptions.html] + def create_dhcp_options(dhcp_configurations = {}) + params = {} + params.merge!(indexed_multidimensional_params(dhcp_configurations)) + request({ + 'Action' => 'CreateDhcpOptions', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::CreateDhcpOptions.new + }.merge!(params)) + end + private + def indexed_multidimensional_params(multi_params) + params = {} + multi_params.keys.each_with_index do |key, key_index| + key_index += 1 + params[format('DhcpConfiguration.%d.Key', key_index)] = key + [*multi_params[key]].each_with_index do |value, value_index| + value_index += 1 + params[format('DhcpConfiguration.%d.Value.%d', key_index, value_index)] = value + end + end + params + end + end + class Mock + def create_dhcp_options(dhcp_configurations = {}) + params = {} + params.merge!(indexed_multidimensional_params(dhcp_configurations)) + Excon::Response.new.tap do |response| + response.status = 200 + self.data[:dhcp_options].push({ + 'dhcpOptionsId' => Fog::AWS::Mock.dhcp_options_id, + 'dhcpConfigurationSet' => {}, + 'tagSet' => {} + }) + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'dhcpOptionsSet' => self.data[:dhcp_options] + } + end + end + private + def indexed_multidimensional_params(multi_params) + params = {} + multi_params.keys.each_with_index do |key, key_index| + key_index += 1 + params[format('DhcpConfiguration.%d.Key', key_index)] = key + [*multi_params[key]].each_with_index do |value, value_index| + value_index += 1 + params[format('DhcpConfiguration.%d.Value.%d', key_index, value_index)] = value + end + end + params + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_image.rb b/lib/fog/aws/requests/compute/create_image.rb new file mode 100644 index 000000000..5d328c56d --- /dev/null +++ b/lib/fog/aws/requests/compute/create_image.rb @@ -0,0 +1,91 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_image' + + # Create a bootable EBS volume AMI + # + # ==== Parameters + # * instance_id<~String> - Instance used to create image. + # * name<~Name> - Name to give image. + # * description<~Name> - Description of image. + # * no_reboot<~Boolean> - Optional, whether or not to reboot the image when making the snapshot + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'imageId'<~String> - The ID of the created AMI. + # * 'requestId'<~String> - Id of request. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateImage.html] + def create_image(instance_id, name, description, no_reboot = false, options={}) + params = {} + block_device_mappings = options[:block_device_mappings] || [] + + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.DeviceName', block_device_mappings.map{|mapping| mapping['DeviceName']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.NoDevice', block_device_mappings.map{|mapping| mapping['NoDevice']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.VirtualName', block_device_mappings.map{|mapping| mapping['VirtualName']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.SnapshotId', block_device_mappings.map{|mapping| mapping['Ebs.SnapshotId']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.DeleteOnTermination', block_device_mappings.map{|mapping| mapping['Ebs.DeleteOnTermination']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.VolumeType', block_device_mappings.map{|mapping| mapping['Ebs.VolumeType']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.Encrypted', block_device_mappings.map{|mapping| mapping['Ebs.Encrypted']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.Iops', block_device_mappings.map{|mapping| mapping['Ebs.Iops']}) + params.reject!{|k,v| v.nil?} + + request({ + 'Action' => 'CreateImage', + 'InstanceId' => instance_id, + 'Name' => name, + 'Description' => description, + 'NoReboot' => no_reboot.to_s, + :parser => Fog::Parsers::Compute::AWS::CreateImage.new + }.merge!(params)) + end + end + + class Mock + # Usage + # + # Aws[:compute].create_image("i-ac65ee8c", "test", "something") + # + + def create_image(instance_id, name, description, no_reboot = false, options = {}) + params = {} + block_device_mappings = options[:block_device_mappings] || [] + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.DeviceName', block_device_mappings.map{|mapping| mapping['DeviceName']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.NoDevice', block_device_mappings.map{|mapping| mapping['NoDevice']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.VirtualName', block_device_mappings.map{|mapping| mapping['VirtualName']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.SnapshotId', block_device_mappings.map{|mapping| mapping['Ebs.SnapshotId']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.DeleteOnTermination', block_device_mappings.map{|mapping| mapping['Ebs.DeleteOnTermination']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.VolumeType', block_device_mappings.map{|mapping| mapping['Ebs.VolumeType']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.Encrypted', block_device_mappings.map{|mapping| mapping['Ebs.Encrypted']}) + params.merge!Fog::AWS.indexed_param('BlockDeviceMapping.%d.Ebs.Iops', block_device_mappings.map{|mapping| mapping['Ebs.Iops']}) + params.reject!{|k,v| v.nil?} + + reserved_ebs_root_device = '/dev/sda1' + block_devices = options.delete(:block_device_mappings) || [] + register_image_response = register_image(name, description, reserved_ebs_root_device, block_devices, options) + + response = Excon::Response.new + if instance_id && !name.empty? + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'imageId' => register_image_response.body['imageId'] + } + else + response.status = 400 + response.body = { + 'Code' => 'InvalidParameterValue' + } + if name.empty? + response.body['Message'] = "Invalid value '' for name. Must be specified." + end + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_internet_gateway.rb b/lib/fog/aws/requests/compute/create_internet_gateway.rb new file mode 100644 index 000000000..fa18cac31 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_internet_gateway.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_internet_gateway' + + # Creates an InternetGateway + # + # ==== Parameters + # (none) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'internetGateway'<~Array>: + # * 'attachmentSet'<~Array>: A list of VPCs attached to the Internet gateway + # * 'vpcId'<~String> - The ID of the VPC the Internet gateway is attached to. + # * 'state'<~String> - The current state of the attachment. + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-ItemType-InternetGatewayAttachmentType.html] + def create_internet_gateway() + request({ + 'Action' => 'CreateInternetGateway', + :parser => Fog::Parsers::Compute::AWS::CreateInternetGateway.new + }) + end + end + + class Mock + def create_internet_gateway() + gateway_id = Fog::AWS::Mock.internet_gateway_id + self.data[:internet_gateways][gateway_id] = { + 'internetGatewayId' => gateway_id, + 'attachmentSet' => {}, + 'tagSet' => {} + } + Excon::Response.new( + :status => 200, + :body => { + 'requestId' => Fog::AWS::Mock.request_id, + 'internetGatewaySet' => [self.data[:internet_gateways][gateway_id]] + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_key_pair.rb b/lib/fog/aws/requests/compute/create_key_pair.rb new file mode 100644 index 000000000..01723d254 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_key_pair.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_key_pair' + + # Create a new key pair + # + # ==== Parameters + # * key_name<~String> - Unique name for key pair. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'keyFingerprint'<~String> - SHA-1 digest of DER encoded private key + # * 'keyMaterial'<~String> - Unencrypted encoded PEM private key + # * 'keyName'<~String> - Name of key + # * 'requestId'<~String> - Id of request + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateKeyPair.html] + def create_key_pair(key_name) + request( + 'Action' => 'CreateKeyPair', + 'KeyName' => key_name, + :parser => Fog::Parsers::Compute::AWS::CreateKeyPair.new + ) + end + end + + class Mock + def create_key_pair(key_name) + response = Excon::Response.new + unless self.data[:key_pairs][key_name] + response.status = 200 + data = { + 'keyFingerprint' => Fog::AWS::Mock.key_fingerprint, + 'keyMaterial' => Fog::AWS::Mock.key_material, + 'keyName' => key_name + } + self.data[:key_pairs][key_name] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + response + else + raise Fog::Compute::AWS::Error.new("InvalidKeyPair.Duplicate => The keypair '#{key_name}' already exists.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_network_acl.rb b/lib/fog/aws/requests/compute/create_network_acl.rb new file mode 100644 index 000000000..b3d5e0ac0 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_network_acl.rb @@ -0,0 +1,105 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_network_acl' + + # Creates a network ACL + # + # ==== Parameters + # * vpcId<~String> - The ID of the VPC to create this network ACL under + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'networkAcl'<~Array>: - The network ACL + # * 'networkAclId'<~String> - The ID of the network ACL + # * 'vpcId'<~String> - The ID of the VPC for the network ACL + # * 'default'<~Boolean> - Indicates whether this is the default network ACL for the VPC + # * 'entrySet'<~Array>: - A list of entries (rules) in the network ACL + # * 'ruleNumber'<~Integer> - The rule number for the entry. ACL entries are processed in ascending order by rule number + # * 'protocol'<~Integer> - The protocol. A value of -1 means all protocols + # * 'ruleAction'<~String> - Indicates whether to allow or deny the traffic that matches the rule + # * 'egress'<~Boolean> - Indicates whether the rule is an egress rule (applied to traffic leaving the subnet) + # * 'cidrBlock'<~String> - The network range to allow or deny, in CIDR notation + # * 'icmpTypeCode'<~Hash> - ICMP protocol: The ICMP type and code + # * 'code'<~Integer> - The ICMP code. A value of -1 means all codes for the specified ICMP type + # * 'type'<~Integer> - The ICMP type. A value of -1 means all types + # * 'portRange'<~Hash> - TCP or UDP protocols: The range of ports the rule applies to + # * 'from'<~Integer> - The first port in the range + # * 'to'<~Integer> - The last port in the range + # * 'associationSet'<~Array>: - A list of associations between the network ACL and subnets + # * 'networkAclAssociationId'<~String> - The ID of the association + # * 'networkAclId'<~String> - The ID of the network ACL + # * 'subnetId'<~String> - The ID of the subnet + # * 'tagSet'<~Array>: - Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-CreateNetworkAcl.html] + def create_network_acl(vpcId, options = {}) + request({ + 'Action' => 'CreateNetworkAcl', + 'VpcId' => vpcId, + :parser => Fog::Parsers::Compute::AWS::CreateNetworkAcl.new + }.merge!(options)) + end + end + + class Mock + def create_network_acl(vpcId, options = {}) + response = Excon::Response.new + if vpcId + id = Fog::AWS::Mock.network_acl_id + + unless self.data[:vpcs].find { |s| s['vpcId'] == vpcId } + raise Fog::Compute::AWS::Error.new("Unknown VPC '#{vpcId}' specified") + end + + data = { + 'networkAclId' => id, + 'vpcId' => vpcId, + 'default' => false, + 'entrySet' => [ + { + 'icmpTypeCode' => {}, + 'portRange' => {}, + 'ruleNumber' => 32767, + 'protocol' => -1, + 'ruleAction' => "deny", + 'egress' => true, + 'cidrBlock' => "0.0.0.0/0", + }, + { + 'icmpTypeCode' => {}, + 'portRange' => {}, + 'ruleNumber' => 32767, + 'protocol' => -1, + 'ruleAction' => "deny", + 'egress' => false, + 'cidrBlock' => "0.0.0.0/0", + }, + ], + 'associationSet' => [], + 'tagSet' => {} + } + + self.data[:network_acls][id] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'networkAcl' => data + } + else + response.status = 400 + response.body = { + 'Code' => 'InvalidParameterValue', + 'Message' => "Invalid value '' for subnetId" + } + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_network_acl_entry.rb b/lib/fog/aws/requests/compute/create_network_acl_entry.rb new file mode 100644 index 000000000..1b5d24b1b --- /dev/null +++ b/lib/fog/aws/requests/compute/create_network_acl_entry.rb @@ -0,0 +1,80 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Creates a Network ACL entry + # + # ==== Parameters + # * network_acl_id<~String> - The ID of the ACL to add this entry to + # * rule_number<~Integer> - The rule number for the entry, between 100 and 32766 + # * protocol<~Integer> - The IP protocol to which the rule applies. You can use -1 to mean all protocols. + # * rule_action<~String> - Allows or denies traffic that matches the rule. (either allow or deny) + # * cidr_block<~String> - The CIDR range to allow or deny + # * egress<~Boolean> - Indicates whether this rule applies to egress traffic from the subnet (true) or ingress traffic to the subnet (false). + # * options<~Hash>: + # * 'Icmp.Code' - ICMP code, required if protocol is 1 + # * 'Icmp.Type' - ICMP type, required if protocol is 1 + # * 'PortRange.From' - The first port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # * 'PortRange.To' - The last port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-CreateNetworkAclEntry.html] + def create_network_acl_entry(network_acl_id, rule_number, protocol, rule_action, cidr_block, egress, options = {}) + request({ + 'Action' => 'CreateNetworkAclEntry', + 'NetworkAclId' => network_acl_id, + 'RuleNumber' => rule_number, + 'Protocol' => protocol, + 'RuleAction' => rule_action, + 'Egress' => egress, + 'CidrBlock' => cidr_block, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(options)) + end + end + + class Mock + def create_network_acl_entry(network_acl_id, rule_number, protocol, rule_action, cidr_block, egress, options = {}) + response = Excon::Response.new + if self.data[:network_acls][network_acl_id] + + if self.data[:network_acls][network_acl_id]['entrySet'].find { |r| r['ruleNumber'] == rule_number && r['egress'] == egress } + raise Fog::Compute::AWS::Error.new("Already a rule with that number") + end + + data = { + 'ruleNumber' => rule_number, + 'protocol' => protocol, + 'ruleAction' => rule_action, + 'egress' => egress, + 'cidrBlock' => cidr_block, + 'icmpTypeCode' => {}, + 'portRange' => {} + } + data['icmpTypeCode']['code'] = options['Icmp.Code'] if options['Icmp.Code'] + data['icmpTypeCode']['type'] = options['Icmp.Type'] if options['Icmp.Type'] + data['portRange']['from'] = options['PortRange.From'] if options['PortRange.From'] + data['portRange']['to'] = options['PortRange.To'] if options['PortRange.To'] + self.data[:network_acls][network_acl_id]['entrySet'] << data + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network ACL '#{network_acl_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_network_interface.rb b/lib/fog/aws/requests/compute/create_network_interface.rb new file mode 100644 index 000000000..903abbbf9 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_network_interface.rb @@ -0,0 +1,134 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_network_interface' + + # Creates a network interface + # + # ==== Parameters + # * subnetId<~String> - The ID of the subnet to associate with the network interface + # * options<~Hash>: + # * PrivateIpAddress<~String> - The private IP address of the network interface + # * Description<~String> - The description of the network interface + # * GroupSet<~Array> - The security group IDs for use by the network interface + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'networkInterface'<~Hash> - The created network interface + # * 'networkInterfaceId'<~String> - The ID of the network interface + # * 'subnetId'<~String> - The ID of the subnet + # * 'vpcId'<~String> - The ID of the VPC + # * 'availabilityZone'<~String> - The availability zone + # * 'description'<~String> - The description + # * 'ownerId'<~String> - The ID of the person who created the interface + # * 'requesterId'<~String> - The ID ot teh entity requesting this interface + # * 'requesterManaged'<~String> - + # * 'status'<~String> - "available" or "in-use" + # * 'macAddress'<~String> - + # * 'privateIpAddress'<~String> - IP address of the interface within the subnet + # * 'privateDnsName'<~String> - The private DNS name + # * 'sourceDestCheck'<~Boolean> - Flag indicating whether traffic to or from the instance is validated + # * 'groupSet'<~Hash> - Associated security groups + # * 'key'<~String> - ID of associated group + # * 'value'<~String> - Name of associated group + # * 'attachment'<~Hash>: - Describes the way this nic is attached + # * 'attachmentID'<~String> + # * 'instanceID'<~String> + # * 'association'<~Hash>: - Describes an eventual instance association + # * 'attachmentID'<~String> - ID of the network interface attachment + # * 'instanceID'<~String> - ID of the instance attached to the network interface + # * 'publicIp'<~String> - Address of the Elastic IP address bound to the network interface + # * 'ipOwnerId'<~String> - ID of the Elastic IP address owner + # * 'tagSet'<~Array>: - Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/ApiReference-query-CreateNetworkInterface.html] + def create_network_interface(subnetId, options = {}) + if security_groups = options.delete('GroupSet') + options.merge!(Fog::AWS.indexed_param('SecurityGroupId', [*security_groups])) + end + request({ + 'Action' => 'CreateNetworkInterface', + 'SubnetId' => subnetId, + :parser => Fog::Parsers::Compute::AWS::CreateNetworkInterface.new + }.merge!(options)) + end + end + + class Mock + def create_network_interface(subnetId, options = {}) + response = Excon::Response.new + if subnetId + subnet = self.data[:subnets].find{ |s| s['subnetId'] == subnetId } + if subnet.nil? + raise Fog::Compute::AWS::Error.new("Unknown subnet '#{subnetId}' specified") + else + id = Fog::AWS::Mock.network_interface_id + cidr_block = IPAddress.parse(subnet['cidrBlock']) + + groups = {} + if options['GroupSet'] + options['GroupSet'].each do |group_id| + group_obj = self.data[:security_groups].select { |k,v| v['groupId'] == group_id }.first + if group_obj.nil? + raise Fog::Compute::AWS::Error.new("Unknown security group '#{group_id}' specified") + end + groups[group_id] = group_obj + end + end + + if options['PrivateIpAddress'].nil? + # Here we try to act like a DHCP server and pick the first + # available IP (not including the first in the cidr block, + # which is typically reserved for the gateway). + cidr_block.each_host do |p_ip| + unless self.data[:network_interfaces].map{ |ni, ni_conf| ni_conf['privateIpAddress'] }.include?p_ip.to_s || + cidr_block.first == p_ip + options['PrivateIpAddress'] = p_ip.to_s + break + end + end + elsif self.data[:network_interfaces].map{ |ni,ni_conf| ni_conf['privateIpAddress'] }.include?options['PrivateIpAddress'] + raise Fog::Compute::AWS::Error.new('InUse => The specified address is already in use.') + end + + data = { + 'networkInterfaceId' => id, + 'subnetId' => subnetId, + 'vpcId' => 'mock-vpc-id', + 'availabilityZone' => 'mock-zone', + 'description' => options['Description'], + 'ownerId' => '', + 'requesterManaged' => 'false', + 'status' => 'available', + 'macAddress' => '00:11:22:33:44:55', + 'privateIpAddress' => options['PrivateIpAddress'], + 'sourceDestCheck' => true, + 'groupSet' => groups, + 'attachment' => {}, + 'association' => {}, + 'tagSet' => {} + } + self.data[:network_interfaces][id] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'networkInterface' => data + } + response + end + else + response.status = 400 + response.body = { + 'Code' => 'InvalidParameterValue', + 'Message' => "Invalid value '' for subnetId" + } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_placement_group.rb b/lib/fog/aws/requests/compute/create_placement_group.rb new file mode 100644 index 000000000..ab5f0fd91 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_placement_group.rb @@ -0,0 +1,31 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Create a new placement group + # + # ==== Parameters + # * group_name<~String> - Name of the placement group. + # * strategy<~String> - Placement group strategy. Valid options in ['cluster'] + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreatePlacementGroup.html] + def create_placement_group(name, strategy) + request( + 'Action' => 'CreatePlacementGroup', + 'GroupName' => name, + 'Strategy' => strategy, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_route.rb b/lib/fog/aws/requests/compute/create_route.rb new file mode 100755 index 000000000..3d26b0904 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_route.rb @@ -0,0 +1,87 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Creates a route in a route table within a VPC. + # + # ==== Parameters + # * RouteTableId<~String> - The ID of the route table for the route. + # * DestinationCidrBlock<~String> - The CIDR address block used for the destination match. Routing decisions are based on the most specific match. + # * GatewayId<~String> - The ID of an Internet gateway attached to your VPC. + # * InstanceId<~String> - The ID of a NAT instance in your VPC. The operation fails if you specify an instance ID unless exactly one network interface is attached. + # * NetworkInterfaceId<~String> - The ID of a network interface. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of the request + # * 'return'<~Boolean> - Returns true if the request succeeds. Otherwise, returns an error. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-CreateRoute.html] + def create_route(route_table_id, destination_cidr_block, internet_gateway_id=nil, instance_id=nil, network_interface_id=nil) + request_vars = { + 'Action' => 'CreateRoute', + 'RouteTableId' => route_table_id, + 'DestinationCidrBlock' => destination_cidr_block, + :parser => Fog::Parsers::Compute::AWS::Basic.new + } + if internet_gateway_id + request_vars['GatewayId'] = internet_gateway_id + elsif instance_id + request_vars['InstanceId'] = instance_id + elsif network_interface_id + request_vars['NetworkInterfaceId'] = network_interface_id + end + request(request_vars) + end + end + + class Mock + def create_route(route_table_id, destination_cidr_block, internet_gateway_id=nil, instance_id=nil, network_interface_id=nil) + instance_owner_id = nil + route_table = self.data[:route_tables].find { |routetable| routetable["routeTableId"].eql? route_table_id } + if !route_table.nil? && destination_cidr_block + if !internet_gateway_id.nil? || !instance_id.nil? || !network_interface_id.nil? + if !internet_gateway_id.nil? && self.internet_gateways.all('internet-gateway-id'=>internet_gateway_id).first.nil? + raise Fog::Compute::AWS::NotFound.new("The gateway ID '#{internet_gateway_id}' does not exist") + elsif !instance_id.nil? && self.servers.all('instance-id'=>instance_id).first.nil? + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_id}' does not exist") + elsif !network_interface_id.nil? && self.network_interfaces.all('networkInterfaceId'=>network_interface_id).first.nil? + raise Fog::Compute::AWS::NotFound.new("The networkInterface ID '#{network_interface_id}' does not exist") + elsif !route_table['routeSet'].find { |route| route['destinationCidrBlock'].eql? destination_cidr_block }.nil? + raise Fog::Compute::AWS::Error, "RouteAlreadyExists => The route identified by #{destination_cidr_block} already exists." + else + response = Excon::Response.new + route_table['routeSet'].push({ + "destinationCidrBlock" => destination_cidr_block, + "gatewayId" => internet_gateway_id, + "instanceId"=>instance_id, + "instanceOwnerId"=>instance_owner_id, + "networkInterfaceId"=>network_interface_id, + "state" => "pending", + "origin" => "CreateRoute" + }) + response.status = 200 + response.body = { + 'requestId'=> Fog::AWS::Mock.request_id, + 'return' => true + } + response + end + else + message = 'MissingParameter => ' + message << 'The request must contain either a gateway id, a network interface id, or an instance id' + raise Fog::Compute::AWS::Error.new(message) + end + elsif route_table.nil? + raise Fog::Compute::AWS::NotFound.new("The routeTable ID '#{route_table_id}' does not exist") + elsif destination_cidr_block.empty? + raise Fog::Compute::AWS::InvalidParameterValue.new("Value () for parameter destinationCidrBlock is invalid. This is not a valid CIDR block.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_route_table.rb b/lib/fog/aws/requests/compute/create_route_table.rb new file mode 100755 index 000000000..e7b6403f6 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_route_table.rb @@ -0,0 +1,69 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_route_table' + + # Creates a route table for the specified VPC. + # + # ==== Parameters + # * VpcId<~String> - The ID of the VPC. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of the request + # * 'routeTable'<~Array> - Information about the newly created route table + # * 'routeTableId'<~String> + # * 'vpcId'<~String> + # * 'routeSet'<~Array> + # * 'item'<~Array> + # * 'destinationCidrBlock'<~String> - The CIDR address block used for the destination match. + # * 'gatewayId'<~String> - The ID of an Internet gateway attached to your VPC. + # * 'state'<~String> - The state of the route. ['blackhole', 'available'] + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-CreateRouteTable.html] + def create_route_table(vpc_id) + request({ + 'Action' => 'CreateRouteTable', + 'VpcId' => vpc_id, + :parser => Fog::Parsers::Compute::AWS::CreateRouteTable.new + }) + end + end + + class Mock + def create_route_table(vpc_id) + response = Excon::Response.new + vpc = self.data[:vpcs].find { |vpc| vpc["vpcId"].eql? vpc_id } + unless vpc.nil? + response.status = 200 + route_table = { + 'routeTableId' => "rtb-#{Fog::Mock.random_hex(8)}", + 'vpcId' => vpc["vpcId"], + 'routeSet' => [{ + "destinationCidrBlock" => vpc["cidrBlock"], + "gatewayId" => "local", + "instanceId"=>nil, + "instanceOwnerId"=>nil, + "networkInterfaceId"=>nil, + "state" => "pending", + "origin" => "CreateRouteTable" + }], + 'associationSet' => [], + 'tagSet' => {} + } + self.data[:route_tables].push(route_table) + response.body = { + 'requestId'=> Fog::AWS::Mock.request_id, + 'routeTable' => [route_table] + } + response + else + raise Fog::Compute::AWS::NotFound.new("The vpc ID '#{vpc_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_security_group.rb b/lib/fog/aws/requests/compute/create_security_group.rb new file mode 100644 index 000000000..ca011399a --- /dev/null +++ b/lib/fog/aws/requests/compute/create_security_group.rb @@ -0,0 +1,60 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_security_group' + + # Create a new security group + # + # ==== Parameters + # * group_name<~String> - Name of the security group. + # * group_description<~String> - Description of group. + # * vpc_id<~String> - ID of the VPC + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # * 'groupId'<~String> - Id of created group + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateSecurityGroup.html] + def create_security_group(name, description, vpc_id=nil) + request( + 'Action' => 'CreateSecurityGroup', + 'GroupName' => name, + 'GroupDescription' => description, + 'VpcId' => vpc_id, + :parser => Fog::Parsers::Compute::AWS::CreateSecurityGroup.new + ) + end + end + + class Mock + def create_security_group(name, description, vpc_id=nil) + response = Excon::Response.new + unless self.data[:security_groups][name] + data = { + 'groupDescription' => description, + 'groupName' => name, + 'groupId' => Fog::AWS::Mock.security_group_id, + 'ipPermissionsEgress' => [], + 'ipPermissions' => [], + 'ownerId' => self.data[:owner_id], + 'vpcId' => vpc_id + } + self.data[:security_groups][name] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'groupId' => data['groupId'], + 'return' => true + } + response + else + raise Fog::Compute::AWS::Error.new("InvalidGroup.Duplicate => The security group '#{name}' already exists") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_snapshot.rb b/lib/fog/aws/requests/compute/create_snapshot.rb new file mode 100644 index 000000000..20aa79703 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_snapshot.rb @@ -0,0 +1,70 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_snapshot' + + # Create a snapshot of an EBS volume and store it in S3 + # + # ==== Parameters + # * volume_id<~String> - Id of EBS volume to snapshot + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'encrypted'<~Boolean>: The encryption status of the snapshot. + # * 'progress'<~String> - The percentage progress of the snapshot + # * 'requestId'<~String> - id of request + # * 'snapshotId'<~String> - id of snapshot + # * 'startTime'<~Time> - timestamp when snapshot was initiated + # * 'status'<~String> - state of snapshot + # * 'volumeId'<~String> - id of volume snapshot targets + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateSnapshot.html] + def create_snapshot(volume_id, description = nil) + request( + 'Action' => 'CreateSnapshot', + 'Description' => description, + 'VolumeId' => volume_id, + :parser => Fog::Parsers::Compute::AWS::CreateSnapshot.new + ) + end + end + + class Mock + # + # Usage + # + # Aws[:compute].create_snapshot("vol-f7c23423", "latest snapshot") + # + + def create_snapshot(volume_id, description = nil) + response = Excon::Response.new + if volume = self.data[:volumes][volume_id] + response.status = 200 + snapshot_id = Fog::AWS::Mock.snapshot_id + data = { + 'description' => description, + 'encrypted' => false, + 'ownerId' => self.data[:owner_id], + 'progress' => nil, + 'snapshotId' => snapshot_id, + 'startTime' => Time.now, + 'status' => 'pending', + 'volumeId' => volume_id, + 'volumeSize' => volume['size'] + } + self.data[:snapshots][snapshot_id] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + else + response.status = 400 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_spot_datafeed_subscription.rb b/lib/fog/aws/requests/compute/create_spot_datafeed_subscription.rb new file mode 100644 index 000000000..8f616ff82 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_spot_datafeed_subscription.rb @@ -0,0 +1,39 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/spot_datafeed_subscription' + + # Create a spot datafeed subscription + # + # ==== Parameters + # * bucket<~String> - bucket name to store datafeed in + # * prefix<~String> - prefix to store data with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'spotDatafeedSubscription'<~Hash>: + # * 'bucket'<~String> - S3 bucket where data is stored + # * 'fault'<~Hash>: + # * 'code'<~String> - fault code + # * 'reason'<~String> - fault reason + # * 'ownerId'<~String> - Aws id of account owner + # * 'prefix'<~String> - prefix for datafeed items + # * 'state'<~String> - state of datafeed subscription + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateSpotDatafeedSubscription.html] + def create_spot_datafeed_subscription(bucket, prefix) + request( + 'Action' => 'CreateSpotDatafeedSubscription', + 'Bucket' => bucket, + 'Prefix' => prefix, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::SpotDatafeedSubscription.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_subnet.rb b/lib/fog/aws/requests/compute/create_subnet.rb new file mode 100644 index 000000000..e74b81c87 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_subnet.rb @@ -0,0 +1,102 @@ +module Fog + module Compute + class Aws + class Real + require 'ipaddress' + require 'fog/aws/parsers/compute/create_subnet' + + # Creates a Subnet with the CIDR block you specify. + # + # ==== Parameters + # * vpcId<~String> - The ID of the VPC where you want to create the subnet. + # * cidrBlock<~String> - The CIDR block you want the Subnet to cover (e.g., 10.0.0.0/16). + # * options<~Hash>: + # * AvailabilityZone<~String> - The Availability Zone you want the subnet in. Default: Aws selects a zone for you (recommended) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'subnet'<~Array>: + # * 'subnetId'<~String> - The Subnet's ID + # * 'state'<~String> - The current state of the Subnet. ['pending', 'available'] + # * 'cidrBlock'<~String> - The CIDR block the Subnet covers. + # * 'AvailableIpAddressCount'<~Integer> - The number of unused IP addresses in the subnet (the IP addresses for any stopped + # instances are considered unavailable) + # * 'AvailabilityZone'<~String> - The Availability Zone the subnet is in + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2011-07-15/APIReference/ApiReference-query-CreateSubnet.html] + def create_subnet(vpcId, cidrBlock, options = {}) + request({ + 'Action' => 'CreateSubnet', + 'VpcId' => vpcId, + 'CidrBlock' => cidrBlock, + :parser => Fog::Parsers::Compute::AWS::CreateSubnet.new + }.merge!(options)) + end + end + + class Mock + def create_subnet(vpcId, cidrBlock, options = {}) + av_zone = options['AvailabilityZone'].nil? ? 'us-east-1c' : options['AvailabilityZone'] + Excon::Response.new.tap do |response| + if cidrBlock && vpcId + vpc = self.data[:vpcs].find{ |v| v['vpcId'] == vpcId } + if vpc.nil? + raise Fog::Compute::AWS::NotFound.new("The vpc ID '#{vpcId}' does not exist") + end + if ! ::IPAddress.parse(vpc['cidrBlock']).include?(::IPAddress.parse(cidrBlock)) + raise Fog::Compute::AWS::Error.new("Range => The CIDR '#{cidrBlock}' is invalid.") + end + self.data[:subnets].select{ |s| s['vpcId'] == vpcId }.each do |subnet| + if ::IPAddress.parse(subnet['cidrBlock']).include?(::IPAddress.parse(cidrBlock)) + raise Fog::Compute::AWS::Error.new("Conflict => The CIDR '#{cidrBlock}' conflicts with another subnet") + end + end + + response.status = 200 + data = { + 'subnetId' => Fog::AWS::Mock.subnet_id, + 'state' => 'pending', + 'vpcId' => vpcId, + 'cidrBlock' => cidrBlock, + 'availableIpAddressCount' => "255", + 'availabilityZone' => av_zone, + 'tagSet' => {} + } + + # Add this subnet to the default network ACL + accid = Fog::AWS::Mock.network_acl_association_id + default_nacl = self.data[:network_acls].values.find { |nacl| nacl['vpcId'] == vpcId && nacl['default'] } + default_nacl['associationSet'] << { + 'networkAclAssociationId' => accid, + 'networkAclId' => default_nacl['networkAclId'], + 'subnetId' => data['subnetId'], + } + + self.data[:subnets].push(data) + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'subnet' => data, + } + else + response.status = 400 + response.body = { + 'Code' => 'InvalidParameterValue' + } + if cidrBlock.empty? + response.body['Message'] = "Invalid value '' for cidrBlock. Must be specified." + end + if vpcId.empty? + response.body['Message'] = "Invalid value '' for vpcId. Must be specified." + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_tags.rb b/lib/fog/aws/requests/compute/create_tags.rb new file mode 100644 index 000000000..56875b35b --- /dev/null +++ b/lib/fog/aws/requests/compute/create_tags.rb @@ -0,0 +1,65 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Adds tags to resources + # + # ==== Parameters + # * resources<~String> - One or more resources to tag + # * tags<~String> - hash of key value tag pairs to assign + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateTags.html] + def create_tags(resources, tags) + resources = [*resources] + for key, value in tags + if value.nil? + tags[key] = '' + end + end + params = {} + params.merge!(Fog::AWS.indexed_param('ResourceId', resources)) + params.merge!(Fog::AWS.indexed_param('Tag.%d.Key', tags.keys)) + params.merge!(Fog::AWS.indexed_param('Tag.%d.Value', tags.values)) + request({ + 'Action' => 'CreateTags', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + end + + class Mock + def create_tags(resources, tags) + resources = [*resources] + tagged = tagged_resources(resources) + + tags.each do |key, value| + self.data[:tags][key] ||= {} + self.data[:tags][key][value] ||= [] + self.data[:tags][key][value] |= tagged + + tagged.each do |resource| + self.data[:tag_sets][resource['resourceId']][key] = value + end + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_volume.rb b/lib/fog/aws/requests/compute/create_volume.rb new file mode 100644 index 000000000..c4b504f51 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_volume.rb @@ -0,0 +1,124 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_volume' + + # Create an EBS volume + # + # ==== Parameters + # * availability_zone<~String> - availability zone to create volume in + # * size<~Integer> - Size in GiBs for volume. Must be between 1 and 1024. + # * options<~Hash> + # * 'SnapshotId'<~String> - Optional, snapshot to create volume from + # * 'VolumeType'<~String> - Optional, volume type. standard or io1, default is standard. + # * 'Iops'<~Integer> - Number of IOPS the volume supports. Required if VolumeType is io1, must be between 1 and 4000. + # * 'Encrypted'<~Boolean> - Optional, specifies whether the volume should be encrypted, default is false. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'availabilityZone'<~String> - Availability zone for volume + # * 'createTime'<~Time> - Timestamp for creation + # * 'size'<~Integer> - Size in GiBs for volume + # * 'snapshotId'<~String> - Snapshot volume was created from, if any + # * 'status'<~String> - State of volume + # * 'volumeId'<~String> - Reference to volume + # * 'volumeType'<~String> - Type of volume + # * 'iops'<~Integer> - Number of IOPS the volume supports + # * 'encrypted'<~Boolean> - Indicates whether the volume will be encrypted + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-CreateVolume.html] + def create_volume(availability_zone, size, options = {}) + unless options.is_a?(Hash) + Fog::Logger.deprecation("create_volume with a bare snapshot_id is deprecated, use create_volume(availability_zone, size, 'SnapshotId' => snapshot_id) instead [light_black](#{caller.first})[/]") + options = { 'SnapshotId' => options } + end + + request({ + 'Action' => 'CreateVolume', + 'AvailabilityZone' => availability_zone, + 'Size' => size, + :parser => Fog::Parsers::Compute::AWS::CreateVolume.new + }.merge(options)) + end + end + + class Mock + def create_volume(availability_zone, size, options = {}) + unless options.is_a?(Hash) + Fog::Logger.deprecation("create_volume with a bare snapshot_id is deprecated, use create_volume(availability_zone, size, 'SnapshotId' => snapshot_id) instead [light_black](#{caller.first})[/]") + options = { 'SnapshotId' => options } + end + + response = Excon::Response.new + if availability_zone && (size || options['SnapshotId']) + snapshot = self.data[:snapshots][options['SnapshotId']] + if options['SnapshotId'] && !snapshot + raise Fog::Compute::AWS::NotFound.new("The snapshot '#{options['SnapshotId']}' does not exist.") + end + + if snapshot && size && size < snapshot['volumeSize'] + raise Fog::Compute::AWS::NotFound.new("The snapshot '#{options['SnapshotId']}' has size #{snapshot['volumeSize']} which is greater than #{size}.") + elsif snapshot && !size + size = snapshot['volumeSize'] + end + + if options['VolumeType'] == 'io1' + iops = options['Iops'] + if !iops + raise Fog::Compute::AWS::Error.new("InvalidParameterCombination => The parameter iops must be specified for io1 volumes.") + end + + if size < 10 + raise Fog::Compute::AWS::Error.new("InvalidParameterValue => Volume of #{size}GiB is too small; minimum is 10GiB.") + end + + if (iops_to_size_ratio = iops.to_f / size.to_f) > 30.0 + raise Fog::Compute::AWS::Error.new("InvalidParameterValue => Iops to volume size ratio of #{"%.1f" % iops_to_size_ratio} is too high; maximum is 30.0") + end + + if iops < 100 + raise Fog::Compute::AWS::Error.new("VolumeIOPSLimit => Volume iops of #{iops} is too low; minimum is 100.") + end + + if iops > 4000 + raise Fog::Compute::AWS::Error.new("VolumeIOPSLimit => Volume iops of #{iops} is too high; maximum is 4000.") + end + end + + response.status = 200 + volume_id = Fog::AWS::Mock.volume_id + data = { + 'availabilityZone' => availability_zone, + 'attachmentSet' => [], + 'createTime' => Time.now, + 'iops' => options['Iops'], + 'encrypted' => options['Encrypted'] || false, + 'size' => size, + 'snapshotId' => options['SnapshotId'], + 'status' => 'creating', + 'volumeId' => volume_id, + 'volumeType' => options['VolumeType'] || 'standard' + } + self.data[:volumes][volume_id] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data.reject {|key,value| !['availabilityZone','createTime','encrypted','size','snapshotId','status','volumeId','volumeType'].include?(key) }) + else + response.status = 400 + response.body = { + 'Code' => 'MissingParameter' + } + unless availability_zone + response.body['Message'] = 'The request must contain the parameter availability_zone' + else + response.body['Message'] = 'The request must contain the parameter size' + end + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/create_vpc.rb b/lib/fog/aws/requests/compute/create_vpc.rb new file mode 100644 index 000000000..333991713 --- /dev/null +++ b/lib/fog/aws/requests/compute/create_vpc.rb @@ -0,0 +1,94 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/create_vpc' + + # Creates a VPC with the CIDR block you specify. + # + # ==== Parameters + # * cidrBlock<~String> - The CIDR block you want the VPC to cover (e.g., 10.0.0.0/16). + # * options<~Hash>: + # * InstanceTenancy<~String> - The allowed tenancy of instances launched into the VPC. A value of default + # means instances can be launched with any tenancy; a value of dedicated means instances must be launched with tenancy as dedicated. + # please not that the documentation is incorrect instanceTenancy will not work while InstanceTenancy will + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'vpc'<~Array>: + # * 'vpcId'<~String> - The VPC's ID + # * 'state'<~String> - The current state of the VPC. ['pending', 'available'] + # * 'cidrBlock'<~String> - The CIDR block the VPC covers. + # * 'dhcpOptionsId'<~String> - The ID of the set of DHCP options. + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2011-07-15/APIReference/index.html?ApiReference-query-CreateVpc.html] + def create_vpc(cidrBlock, options = {}) + request({ + 'Action' => 'CreateVpc', + 'CidrBlock' => cidrBlock, + :parser => Fog::Parsers::Compute::AWS::CreateVpc.new + }.merge!(options)) + end + end + + class Mock + def create_vpc(cidrBlock) + Excon::Response.new.tap do |response| + if cidrBlock + response.status = 200 + vpc_id = Fog::AWS::Mock.vpc_id + vpc = { + 'vpcId' => vpc_id, + 'state' => 'pending', + 'cidrBlock' => cidrBlock, + 'dhcpOptionsId' => Fog::AWS::Mock.request_id, + 'tagSet' => {}, + 'enableDnsSupport' => true, + 'enableDnsHostnames' => false, + 'mapPublicIpOnLaunch'=> false + } + self.data[:vpcs].push(vpc) + + #Creates a default route for the subnet + default_route = self.route_tables.new(:vpc_id => vpc_id) + default_route.save + + # You are not able to push a main route in the normal Aws, so we are re-implementing some of the + # associate_route_table here in order to accomplish this. + route_table = self.data[:route_tables].find { |routetable| routetable["routeTableId"].eql? default_route.id } + + # This pushes a main route to the associationSet + # add_route_association(routeTableId, subnetId, main=false) is declared in assocate_route_table.rb + assoc = add_route_association(default_route.id, nil, true) + route_table["associationSet"].push(assoc) + + # Create a default network ACL + default_nacl = self.network_acls.new(:vpc_id => vpc_id) + default_nacl.save + # Manually override since Amazon doesn't let you create a default one + self.data[:network_acls][default_nacl.network_acl_id]['default'] = true + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'vpcSet' => [vpc] + } + else + response.status = 400 + response.body = { + 'Code' => 'InvalidParameterValue' + } + if cidrBlock.empty? + response.body['Message'] = "Invalid value '' for cidrBlock. Must be specified." + end + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_dhcp_options.rb b/lib/fog/aws/requests/compute/delete_dhcp_options.rb new file mode 100644 index 000000000..23f3e19bd --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_dhcp_options.rb @@ -0,0 +1,50 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + #Deletes a set of DHCP options that you specify. Amazon VPC returns an error if the set of options you specify is currently + #associated with a VPC. You can disassociate the set of options by associating either a new set of options or the default + #options with the VPC. + # + # ==== Parameters + # * dhcp_options_id<~String> - The ID of the DHCP options set you want to delete. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteDhcpOptions.html] + def delete_dhcp_options(dhcp_options_id) + request( + 'Action' => 'DeleteDhcpOptions', + 'DhcpOptionsId' => dhcp_options_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_dhcp_options(dhcp_options_id) + Excon::Response.new.tap do |response| + if dhcp_options_id + response.status = 200 + self.data[:dhcp_options].reject! { |v| v['dhcpOptionsId'] == dhcp_options_id } + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + else + message = 'MissingParameter => ' + message << 'The request must contain the parameter dhcp_options_id' + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_internet_gateway.rb b/lib/fog/aws/requests/compute/delete_internet_gateway.rb new file mode 100644 index 000000000..1b9841a9f --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_internet_gateway.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + #Deletes an Internet gateway from your Aws account. The gateway must not be attached to a VPC + # + # ==== Parameters + # * internet_gateway_id<~String> - The ID of the InternetGateway you want to delete. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteInternetGateway.html] + def delete_internet_gateway(internet_gateway_id) + request( + 'Action' => 'DeleteInternetGateway', + 'InternetGatewayId' => internet_gateway_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_internet_gateway(internet_gateway_id) + Excon::Response.new.tap do |response| + if internet_gateway_id + response.status = 200 + self.data[:internet_gateways].delete(internet_gateway_id) + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + else + message = 'MissingParameter => ' + message << 'The request must contain the parameter internet_gateway_id' + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_key_pair.rb b/lib/fog/aws/requests/compute/delete_key_pair.rb new file mode 100644 index 000000000..3d94b409c --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_key_pair.rb @@ -0,0 +1,43 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Delete a key pair that you own + # + # ==== Parameters + # * key_name<~String> - Name of the key pair. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteKeyPair.html] + def delete_key_pair(key_name) + request( + 'Action' => 'DeleteKeyPair', + 'KeyName' => key_name, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_key_pair(key_name) + response = Excon::Response.new + self.data[:key_pairs].delete(key_name) + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_network_acl.rb b/lib/fog/aws/requests/compute/delete_network_acl.rb new file mode 100644 index 000000000..eda1d7e25 --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_network_acl.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Deletes a network ACL. + # + # ==== Parameters + # * network_acl_id<~String> - The ID of the network ACL you want to delete. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteNetworkAcl.html] + def delete_network_acl(network_acl_id) + request( + 'Action' => 'DeleteNetworkAcl', + 'NetworkAclId' => network_acl_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_network_acl(network_acl_id) + response = Excon::Response.new + if self.data[:network_acls][network_acl_id] + + if self.data[:network_acls][network_acl_id]['associationSet'].any? + raise Fog::Compute::AWS::Error.new("ACL is in use") + end + + self.data[:network_acls].delete(network_acl_id) + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network ACL '#{network_acl_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_network_acl_entry.rb b/lib/fog/aws/requests/compute/delete_network_acl_entry.rb new file mode 100644 index 000000000..198dd6d7e --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_network_acl_entry.rb @@ -0,0 +1,55 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Deletes a network ACL entry + # + # ==== Parameters + # * network_acl_id<~String> - The ID of the network ACL + # * rule_number<~Integer> - The rule number of the entry to delete. + # * egress<~Boolean> - Indicates whether the rule is an egress rule (true) or ingress rule (false) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteNetworkAclEntry.html] + def delete_network_acl_entry(network_acl_id, rule_number, egress) + request( + 'Action' => 'DeleteNetworkAclEntry', + 'NetworkAclId' => network_acl_id, + 'RuleNumber' => rule_number, + 'Egress' => egress, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_network_acl_entry(network_acl_id, rule_number, egress) + response = Excon::Response.new + if self.data[:network_acls][network_acl_id] + if self.data[:network_acls][network_acl_id]['entrySet'].find { |r| r['ruleNumber'] == rule_number && r['egress'] == egress } + self.data[:network_acls][network_acl_id]['entrySet'].delete_if { |r| r['ruleNumber'] == rule_number && r['egress'] == egress } + else + raise Fog::Compute::AWS::Error.new("No rule with that number and egress value") + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network ACL '#{network_acl_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_network_interface.rb b/lib/fog/aws/requests/compute/delete_network_interface.rb new file mode 100644 index 000000000..3963c899c --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_network_interface.rb @@ -0,0 +1,51 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + # Deletes a network interface. + # + # ==== Parameters + # * network_interface_id<~String> - The ID of the network interface you want to delete. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/ApiReference-query-DeleteNetworkInterface.html] + def delete_network_interface(network_interface_id) + request( + 'Action' => 'DeleteNetworkInterface', + 'NetworkInterfaceId' => network_interface_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_network_interface(network_interface_id) + response = Excon::Response.new + if self.data[:network_interfaces][network_interface_id] + + if self.data[:network_interfaces][network_interface_id]['attachment']['attachmentId'] + raise Fog::Compute::AWS::Error.new("Interface is in use") + end + + self.data[:network_interfaces].delete(network_interface_id) + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network interface '#{network_interface_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_placement_group.rb b/lib/fog/aws/requests/compute/delete_placement_group.rb new file mode 100644 index 000000000..9e93d2cf4 --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_placement_group.rb @@ -0,0 +1,30 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Delete a placement group that you own + # + # ==== Parameters + # * group_name<~String> - Name of the placement group. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeletePlacementGroup.html] + def delete_placement_group(name) + request( + 'Action' => 'DeletePlacementGroup', + 'GroupName' => name, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_route.rb b/lib/fog/aws/requests/compute/delete_route.rb new file mode 100755 index 000000000..2f3fe3e30 --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_route.rb @@ -0,0 +1,57 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Deletes the specified route from the specified route table. + # + # ==== Parameters + # * RouteTableId<~String> - The ID of the route table. + # * DestinationCidrBlock<~String> - The CIDR range for the route. The value you specify must match the CIDR for the route exactly. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - The ID of the request. + # * 'return'<~Boolean> - Returns true if the request succeeds. Otherwise, returns an error. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteRoute.html] + def delete_route(route_table_id, destination_cidr_block) + request( + 'Action' => 'DeleteRoute', + 'RouteTableId' => route_table_id, + 'DestinationCidrBlock' => destination_cidr_block, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_route(route_table_id, destination_cidr_block) + route_table = self.data[:route_tables].find { |routetable| routetable["routeTableId"].eql? route_table_id } + unless route_table.nil? + route = route_table['routeSet'].find { |route| route["destinationCidrBlock"].eql? destination_cidr_block } + if !route.nil? && route['gatewayId'] != "local" + route_table['routeSet'].delete(route) + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId'=> Fog::AWS::Mock.request_id, + 'return' => true + } + response + elsif route['gatewayId'] == "local" + # Cannot delete the default route + raise Fog::Compute::AWS::Error, "InvalidParameterValue => cannot remove local route #{destination_cidr_block} in route table #{route_table_id}" + else + raise Fog::Compute::AWS::NotFound.new("no route with destination-cidr-block #{destination_cidr_block} in route table #{route_table_id}") + end + else + raise Fog::Compute::AWS::NotFound.new("no route with destination-cidr-block #{destination_cidr_block} in route table #{route_table_id}") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_route_table.rb b/lib/fog/aws/requests/compute/delete_route_table.rb new file mode 100755 index 000000000..2d354375d --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_route_table.rb @@ -0,0 +1,49 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Deletes the specified route table. + # + # ==== Parameters + # * RouteTableId<~String> - The ID of the route table. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - The ID of request. + # * 'return'<~Boolean> - Returns true if the request succeeds. Otherwise, returns an error. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteRouteTable.html] + def delete_route_table(route_table_id) + request( + 'Action' => 'DeleteRouteTable', + 'RouteTableId' => route_table_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_route_table(route_table_id) + route_table = self.data[:route_tables].find { |routetable| routetable["routeTableId"].eql? route_table_id } + if !route_table.nil? && route_table['associationSet'].empty? + self.data[:route_tables].delete(route_table) + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId'=> Fog::AWS::Mock.request_id, + 'return' => true + } + response + elsif route_table.nil? + raise Fog::Compute::AWS::NotFound.new("The routeTable ID '#{route_table_id}' does not exist") + elsif !route_table['associationSet'].empty? + raise Fog::Compute::AWS::Error, "DependencyViolation => The routeTable '#{route_table_id}' has dependencies and cannot be deleted." + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_security_group.rb b/lib/fog/aws/requests/compute/delete_security_group.rb new file mode 100644 index 000000000..e93b8ba5b --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_security_group.rb @@ -0,0 +1,100 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Delete a security group that you own + # + # ==== Parameters + # * group_name<~String> - Name of the security group, must be nil if id is specified + # * group_id<~String> - Id of the security group, must be nil if name is specified + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteSecurityGroup.html] + def delete_security_group(name, id = nil) + if name && id + raise Fog::Compute::AWS::Error.new("May not specify both group_name and group_id") + end + if name + type_id = 'GroupName' + identifier = name + else + type_id = 'GroupId' + identifier = id + end + request( + 'Action' => 'DeleteSecurityGroup', + type_id => identifier, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_security_group(name, id = nil) + if name == 'default' + raise Fog::Compute::AWS::Error.new("InvalidGroup.Reserved => The security group 'default' is reserved") + end + + if name && id + raise Fog::Compute::AWS::Error.new("May not specify both group_name and group_id") + end + if id + name = self.data[:security_groups].reject { |k,v| v['groupId'] != id } .keys.first + end + + response = Excon::Response.new + if self.data[:security_groups][name] + + used_by_groups = [] + self.region_data.each do |access_key, key_data| + key_data[:security_groups].each do |group_name, group| + next if group == self.data[:security_groups][name] + + group['ipPermissions'].each do |group_ip_permission| + group_ip_permission['groups'].each do |group_group_permission| + if group_group_permission['groupName'] == name && + group_group_permission['userId'] == self.data[:owner_id] + used_by_groups << "#{key_data[:owner_id]}:#{group_name}" + end + end + end + end + end + + active_instances = self.data[:instances].values.select do |instance| + if instance['groupSet'].include?(name) && instance['instanceState'] != "terminated" + instance + end + end + + unless used_by_groups.empty? + raise Fog::Compute::AWS::Error.new("InvalidGroup.InUse => Group #{self.data[:owner_id]}:#{name} is used by groups: #{used_by_groups.uniq.join(" ")}") + end + + if active_instances.any? + raise Fog::Compute::AWS::Error.new("InUse => There are active instances using security group '#{name}'") + end + + self.data[:security_groups].delete(name) + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The security group '#{name}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_snapshot.rb b/lib/fog/aws/requests/compute/delete_snapshot.rb new file mode 100644 index 000000000..868cb4f82 --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_snapshot.rb @@ -0,0 +1,46 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Delete a snapshot of an EBS volume that you own + # + # ==== Parameters + # * snapshot_id<~String> - ID of snapshot to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteSnapshot.html] + def delete_snapshot(snapshot_id) + request( + 'Action' => 'DeleteSnapshot', + 'SnapshotId' => snapshot_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_snapshot(snapshot_id) + response = Excon::Response.new + if snapshot = self.data[:snapshots].delete(snapshot_id) + response.status = true + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The snapshot '#{snapshot_id}' does not exist.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_spot_datafeed_subscription.rb b/lib/fog/aws/requests/compute/delete_spot_datafeed_subscription.rb new file mode 100644 index 000000000..8db549b34 --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_spot_datafeed_subscription.rb @@ -0,0 +1,26 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Delete a spot datafeed subscription + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteSpotDatafeedSubscription.html] + def delete_spot_datafeed_subscription + request( + 'Action' => 'DeleteSpotDatafeedSubscription', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_subnet.rb b/lib/fog/aws/requests/compute/delete_subnet.rb new file mode 100644 index 000000000..74d0aab3f --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_subnet.rb @@ -0,0 +1,49 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + # Deletes a subnet from a VPC. You must terminate all running instances in the subnet before deleting it, otherwise Amazon + # VPC returns an error + # + # ==== Parameters + # * subnet_id<~String> - The ID of the Subnet you want to delete. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2011-07-15/APIReference/ApiReference-query-DeleteSubnet.html] + def delete_subnet(subnet_id) + request( + 'Action' => 'DeleteSubnet', + 'SubnetId' => subnet_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_subnet(subnet_id) + Excon::Response.new.tap do |response| + if subnet_id + self.data[:subnets].reject! { |v| v['subnetId'] == subnet_id } + response.status = 200 + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + else + message = 'MissingParameter => ' + message << 'The request must contain the parameter subnet_id' + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_tags.rb b/lib/fog/aws/requests/compute/delete_tags.rb new file mode 100644 index 000000000..3ad786a22 --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_tags.rb @@ -0,0 +1,67 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Remove tags from resources + # + # ==== Parameters + # * resources<~String> - One or more resources to remove tags from + # * tags<~String> - hash of key value tag pairs to remove + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteTags.html] + def delete_tags(resources, tags) + resources = [*resources] + params = {} + params.merge!(Fog::AWS.indexed_param('ResourceId', resources)) + + # can not rely on indexed_param because nil values should be omitted + tags.keys.each_with_index do |key, index| + index += 1 # should start at 1 instead of 0 + params.merge!("Tag.#{index}.Key" => key) + unless tags[key].nil? + params.merge!("Tag.#{index}.Value" => tags[key]) + end + end + + request({ + 'Action' => 'DeleteTags', + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + end + + class Mock + def delete_tags(resources, tags) + tagged = tagged_resources(resources) + + tags.each do |key, value| + self.data[:tags][key][value] = self.data[:tags][key][value] - tagged + end + + tagged.each do |resource| + tags.each do |key, value| + tagset = self.data[:tag_sets][resource['resourceId']] + tagset.delete(key) if tagset.key?(key) && (value.nil? || tagset[key] == value) + end + end + + response = Excon::Response.new + response.status = true + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_volume.rb b/lib/fog/aws/requests/compute/delete_volume.rb new file mode 100644 index 000000000..9627b4c4a --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_volume.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Delete an EBS volume + # + # ==== Parameters + # * volume_id<~String> - Id of volume to delete. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeleteVolume.html] + def delete_volume(volume_id) + request( + 'Action' => 'DeleteVolume', + 'VolumeId' => volume_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_volume(volume_id) + response = Excon::Response.new + if volume = self.data[:volumes][volume_id] + if volume["attachmentSet"].any? + attach = volume["attachmentSet"].first + raise Fog::Compute::AWS::Error.new("Client.VolumeInUse => Volume #{volume_id} is currently attached to #{attach["instanceId"]}") + end + self.data[:deleted_at][volume_id] = Time.now + volume['status'] = 'deleting' + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The volume '#{volume_id}' does not exist.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/delete_vpc.rb b/lib/fog/aws/requests/compute/delete_vpc.rb new file mode 100644 index 000000000..4573b04fb --- /dev/null +++ b/lib/fog/aws/requests/compute/delete_vpc.rb @@ -0,0 +1,56 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Deletes a VPC. You must detach or delete all gateways or other objects + # that are dependent on the VPC first. For example, you must terminate + # all running instances, delete all VPC security groups (except the + # default), delete all the route tables (except the default), etc. + # + # ==== Parameters + # * vpc_id<~String> - The ID of the VPC you want to delete. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2011-07-15/APIReference/index.html?ApiReference-query-DeleteVpc.html] + def delete_vpc(vpc_id) + request( + 'Action' => 'DeleteVpc', + 'VpcId' => vpc_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def delete_vpc(vpc_id) + Excon::Response.new.tap do |response| + if vpc_id + response.status = 200 + self.data[:vpcs].reject! { |v| v['vpcId'] == vpc_id } + + # Delete the default network ACL + network_acl_id = self.network_acls.all('vpc-id' => vpc_id, 'default' => true).first.network_acl_id + self.data[:network_acls].delete(network_acl_id) + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + else + message = 'MissingParameter => ' + message << 'The request must contain the parameter vpc_id' + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/deregister_image.rb b/lib/fog/aws/requests/compute/deregister_image.rb new file mode 100644 index 000000000..8379cad7a --- /dev/null +++ b/lib/fog/aws/requests/compute/deregister_image.rb @@ -0,0 +1,49 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/deregister_image' + + # deregister an image + # + # ==== Parameters + # * image_id<~String> - Id of image to deregister + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'return'<~Boolean> - Returns true if deregistration succeeded + # * 'requestId'<~String> - Id of request + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DeregisterImage.html] + def deregister_image(image_id) + request( + 'Action' => 'DeregisterImage', + 'ImageId' => image_id, + :parser => Fog::Parsers::Compute::AWS::DeregisterImage.new + ) + end + end + + class Mock + def deregister_image(image_id) + response = Excon::Response.new + if image_id + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => "true" + } + response + else + message = 'MissingParameter => ' + if !instance_id + message << 'The request must contain the parameter image_id' + end + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_account_attributes.rb b/lib/fog/aws/requests/compute/describe_account_attributes.rb new file mode 100644 index 000000000..3a6d5cd38 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_account_attributes.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_account_attributes' + + # Describe account attributes + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> = Id of request + # * 'accountAttributeSet'<~Array>: + # * 'attributeName'<~String> - supported-platforms + # * 'attributeValueSet'<~Array>: + # * 'attributeValue'<~String> - Value of attribute + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeAccountAttributes.html] + + def describe_account_attributes(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeAccountAttributes', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeAccountAttributes.new + }.merge!(params)) + end + end + + class Mock + def describe_account_attributes(filters = {}) + account_attributes = self.data[:account_attributes] + + Excon::Response.new( + :status => 200, + :body => { + 'requestId' => Fog::AWS::Mock.request_id, + 'accountAttributeSet' => account_attributes + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_addresses.rb b/lib/fog/aws/requests/compute/describe_addresses.rb new file mode 100644 index 000000000..625a516f7 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_addresses.rb @@ -0,0 +1,62 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_addresses' + + # Describe all or specified IP addresses. + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'addressesSet'<~Array>: + # * 'instanceId'<~String> - instance for ip address + # * 'publicIp'<~String> - ip address for instance + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeAddresses.html] + def describe_addresses(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_addresses with #{filters.class} param is deprecated, use describe_addresses('public-ip' => []) instead [light_black](#{caller.first})[/]") + filters = {'public-ip' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeAddresses', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeAddresses.new + }.merge!(params)) + end + end + + class Mock + def describe_addresses(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_addresses with #{filters.class} param is deprecated, use describe_addresses('public-ip' => []) instead [light_black](#{caller.first})[/]") + filters = {'public-ip' => [*filters]} + end + + response = Excon::Response.new + + addresses_set = self.data[:addresses].values + + aliases = {'public-ip' => 'publicIp', 'instance-id' => 'instanceId', 'allocation-id' => 'allocationId'} + for filter_key, filter_value in filters + aliased_key = aliases[filter_key] + addresses_set = addresses_set.reject{|address| ![*filter_value].include?(address[aliased_key])} + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'addressesSet' => addresses_set + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_availability_zones.rb b/lib/fog/aws/requests/compute/describe_availability_zones.rb new file mode 100644 index 000000000..33ea1c3e0 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_availability_zones.rb @@ -0,0 +1,94 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_availability_zones' + + # Describe all or specified availability zones + # + # ==== Params + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'availabilityZoneInfo'<~Array>: + # * 'regionName'<~String> - Name of region + # * 'zoneName'<~String> - Name of zone + # * 'zoneState'<~String> - State of zone + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeAvailabilityZones.html] + def describe_availability_zones(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_availability_zones with #{filters.class} param is deprecated, use describe_availability_zones('zone-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'public-ip' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeAvailabilityZones', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeAvailabilityZones.new + }.merge!(params)) + end + end + + class Mock + def describe_availability_zones(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_availability_zones with #{filters.class} param is deprecated, use describe_availability_zones('zone-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'public-ip' => [*filters]} + end + + response = Excon::Response.new + + all_zones = [ + {"messageSet" => [], "regionName" => "us-east-1", "zoneName" => "us-east-1a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-east-1", "zoneName" => "us-east-1b", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-east-1", "zoneName" => "us-east-1c", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-east-1", "zoneName" => "us-east-1d", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-east-1", "zoneName" => "us-east-1e", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "us-west-1", "zoneName" => "us-west-1a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-west-1", "zoneName" => "us-west-1b", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-west-1", "zoneName" => "us-west-1c", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "us-west-2", "zoneName" => "us-west-2a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "us-west-2", "zoneName" => "us-west-2b", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "sa-east-1", "zoneName" => "sa-east-1a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "sa-east-1", "zoneName" => "sa-east-1b", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "eu-west-1", "zoneName" => "eu-west-1a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "eu-west-1", "zoneName" => "eu-west-1b", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "eu-west-1", "zoneName" => "eu-west-1c", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "ap-northeast-1", "zoneName" => "ap-northeast-1a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "ap-northeast-1", "zoneName" => "ap-northeast-1b", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "ap-southeast-1", "zoneName" => "ap-southeast-1a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "ap-southeast-1", "zoneName" => "ap-southeast-1b", "zoneState" => "available"}, + + {"messageSet" => [], "regionName" => "ap-southeast-2", "zoneName" => "ap-southeast-2a", "zoneState" => "available"}, + {"messageSet" => [], "regionName" => "ap-southeast-2", "zoneName" => "ap-southeast-2b", "zoneState" => "available"}, + ] + + availability_zone_info = all_zones.select { |zoneinfo| zoneinfo["regionName"] == @region } + + aliases = {'region-name' => 'regionName', 'zone-name' => 'zoneName', 'state' => 'zoneState'} + for filter_key, filter_value in filters + aliased_key = aliases[filter_key] + availability_zone_info = availability_zone_info.reject{|availability_zone| ![*filter_value].include?(availability_zone[aliased_key])} + end + + response.status = 200 + response.body = { + 'availabilityZoneInfo' => availability_zone_info, + 'requestId' => Fog::AWS::Mock.request_id + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_dhcp_options.rb b/lib/fog/aws/requests/compute/describe_dhcp_options.rb new file mode 100644 index 000000000..38e55a749 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_dhcp_options.rb @@ -0,0 +1,54 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_dhcp_options' + + # Describe all or specified dhcp_options + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'DhcpOptionsSet'<~Array>: + # * 'dhcpOptionsId'<~String> - The ID of the Dhcp Options + # * 'dhcpConfigurationSet'<~Array>: - The list of options in the set. + # * 'key'<~String> - The name of a DHCP option. + # * 'valueSet'<~Array>: A set of values for a DHCP option. + # * 'value'<~String> - The value of a DHCP option. + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-ItemType-DhcpOptionsType.html] + def describe_dhcp_options(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.warning("describe_dhcp_options with #{filters.class} param is deprecated, use dhcp_options('dhcp-options-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'dhcp-options-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeDhcpOptions', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeDhcpOptions.new + }.merge!(params)) + end + end + + class Mock + def describe_dhcp_options(filters = {}) + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'dhcpOptionsSet' => self.data[:dhcp_options] + } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_images.rb b/lib/fog/aws/requests/compute/describe_images.rb new file mode 100644 index 000000000..4e3081d53 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_images.rb @@ -0,0 +1,126 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_images' + + # Describe all or specified images. + # + # ==== Params + # * filters<~Hash> - List of filters to limit results with + # * filters and/or the following + # * 'ExecutableBy'<~String> - Only return images that the executable_by + # user has explicit permission to launch + # * 'ImageId'<~Array> - Ids of images to describe + # * 'Owner'<~String> - Only return images belonging to owner. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'imagesSet'<~Array>: + # * 'architecture'<~String> - Architecture of the image + # * 'blockDeviceMapping'<~Array> - An array of mapped block devices + # * 'description'<~String> - Description of image + # * 'imageId'<~String> - Id of the image + # * 'imageLocation'<~String> - Location of the image + # * 'imageOwnerAlias'<~String> - Alias of the owner of the image + # * 'imageOwnerId'<~String> - Id of the owner of the image + # * 'imageState'<~String> - State of the image + # * 'imageType'<~String> - Type of the image + # * 'isPublic'<~Boolean> - Whether or not the image is public + # * 'kernelId'<~String> - Kernel id associated with image, if any + # * 'platform'<~String> - Operating platform of the image + # * 'productCodes'<~Array> - Product codes for the image + # * 'ramdiskId'<~String> - Ramdisk id associated with image, if any + # * 'rootDeviceName'<~String> - Root device name, e.g. /dev/sda1 + # * 'rootDeviceType'<~String> - Root device type, ebs or instance-store + # * 'virtualizationType'<~String> - Type of virtualization + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeImages.html] + def describe_images(filters = {}) + options = {} + for key in ['ExecutableBy', 'ImageId', 'Owner'] + if filters.is_a?(Hash) && filters.key?(key) + options.merge!(Fog::AWS.indexed_request_param(key, filters.delete(key))) + end + end + params = Fog::AWS.indexed_filters(filters).merge!(options) + request({ + 'Action' => 'DescribeImages', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeImages.new + }.merge!(params)) + end + end + + class Mock + def describe_images(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_images with #{filters.class} param is deprecated, use describe_images('image-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'image-id' => [*filters]} + end + + if filters.keys.any? {|key| key =~ /^block-device/} + Fog::Logger.warning("describe_images block-device-mapping filters are not yet mocked [light_black](#{caller.first})[/]") + Fog::Mock.not_implemented + end + + if owner = filters.delete('Owner') + if owner == 'self' + filters['owner-id'] = self.data[:owner_id] + else + filters['owner-alias'] = owner + end + end + + response = Excon::Response.new + + aliases = { + 'architecture' => 'architecture', + 'description' => 'description', + 'hypervisor' => 'hypervisor', + 'image-id' => 'imageId', + 'image-type' => 'imageType', + 'is-public' => 'isPublic', + 'kernel-id' => 'kernelId', + 'manifest-location' => 'manifestLocation', + 'name' => 'name', + 'owner-alias' => 'imageOwnerAlias', + 'owner-id' => 'imageOwnerId', + 'ramdisk-id' => 'ramdiskId', + 'root-device-name' => 'rootDeviceName', + 'root-device-type' => 'rootDeviceType', + 'state' => 'imageState', + 'virtualization-type' => 'virtualizationType' + } + + image_set = visible_images.values + image_set = apply_tag_filters(image_set, filters, 'imageId') + + for filter_key, filter_value in filters + aliased_key = aliases[filter_key] + image_set = image_set.reject{|image| ![*filter_value].include?(image[aliased_key])} + end + + image_set = image_set.map do |image| + case image['imageState'] + when 'pending' + if Time.now - image['registered'] >= Fog::Mock.delay + image['imageState'] = 'available' + end + end + image.reject { |key, value| ['registered'].include?(key) }.merge('tagSet' => self.data[:tag_sets][image['imageId']]) + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'imagesSet' => image_set + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_instance_status.rb b/lib/fog/aws/requests/compute/describe_instance_status.rb new file mode 100644 index 000000000..2946ac909 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_instance_status.rb @@ -0,0 +1,46 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_instance_status' + + # http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeInstanceStatus.html + # + def describe_instance_status(filters = {}) + raise ArgumentError.new("Filters must be a hash, but is a #{filters.class}.") unless filters.is_a?(Hash) + next_token = filters.delete('nextToken') || filters.delete('NextToken') + max_results = filters.delete('maxResults') || filters.delete('MaxResults') + all_instances = filters.delete('includeAllInstances') || filters.delete('IncludeAllInstances') + + params = Fog::AWS.indexed_request_param('InstanceId', filters.delete('InstanceId')) + + params.merge!(Fog::AWS.indexed_filters(filters)) + + params['NextToken'] = next_token if next_token + params['MaxResults'] = max_results if max_results + params['IncludeAllInstances'] = all_instances if all_instances + + request({ + 'Action' => 'DescribeInstanceStatus', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeInstanceStatus.new + }.merge!(params)) + end + end + + class Mock + def describe_instance_status(filters = {}) + response = Excon::Response.new + response.status = 200 + + response.body = { + 'instanceStatusSet' => [], + 'requestId' => Fog::AWS::Mock.request_id + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_instances.rb b/lib/fog/aws/requests/compute/describe_instances.rb new file mode 100644 index 000000000..50b2d796b --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_instances.rb @@ -0,0 +1,265 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_instances' + + # Describe all or specified instances + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # * Also allows for passing of optional parameters to fetch instances in batches: + # * 'maxResults' - The number of instances to return for the request + # * 'nextToken' - The token to fetch the next set of items. This is returned by a previous request. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'nextToken' - The token to use when requesting the next set of items when fetching items in batches. + # * 'reservationSet'<~Array>: + # * 'groupSet'<~Array> - Group names for reservation + # * 'ownerId'<~String> - Aws Access Key ID of reservation owner + # * 'reservationId'<~String> - Id of the reservation + # * 'instancesSet'<~Array>: + # * instance<~Hash>: + # * 'architecture'<~String> - architecture of image in [i386, x86_64] + # * 'amiLaunchIndex'<~Integer> - reference to instance in launch group + # * 'blockDeviceMapping'<~Array> + # * 'attachTime'<~Time> - time of volume attachment + # * 'deleteOnTermination'<~Boolean> - whether or not to delete volume on termination + # * 'deviceName'<~String> - specifies how volume is exposed to instance + # * 'status'<~String> - status of attached volume + # * 'volumeId'<~String> - Id of attached volume + # * 'dnsName'<~String> - public dns name, blank until instance is running + # * 'ebsOptimized'<~Boolean> - Whether the instance is optimized for EBS I/O + # * 'imageId'<~String> - image id of ami used to launch instance + # * 'instanceId'<~String> - id of the instance + # * 'instanceState'<~Hash>: + # * 'code'<~Integer> - current status code + # * 'name'<~String> - current status name + # * 'instanceType'<~String> - type of instance + # * 'ipAddress'<~String> - public ip address assigned to instance + # * 'kernelId'<~String> - id of kernel used to launch instance + # * 'keyName'<~String> - name of key used launch instances or blank + # * 'launchTime'<~Time> - time instance was launched + # * 'monitoring'<~Hash>: + # * 'state'<~Boolean - state of monitoring + # * 'placement'<~Hash>: + # * 'availabilityZone'<~String> - Availability zone of the instance + # * 'platform'<~String> - Platform of the instance (e.g., Windows). + # * 'productCodes'<~Array> - Product codes for the instance + # * 'privateDnsName'<~String> - private dns name, blank until instance is running + # * 'privateIpAddress'<~String> - private ip address assigned to instance + # * 'rootDeviceName'<~String> - specifies how the root device is exposed to the instance + # * 'rootDeviceType'<~String> - root device type used by AMI in [ebs, instance-store] + # * 'ramdiskId'<~String> - Id of ramdisk used to launch instance + # * 'reason'<~String> - reason for most recent state transition, or blank + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeInstances.html] + def describe_instances(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_instances with #{filters.class} param is deprecated, use describe_instances('instance-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'instance-id' => [*filters]} + end + params = {} + + next_token = filters.delete('nextToken') || filters.delete('NextToken') + max_results = filters.delete('maxResults') || filters.delete('MaxResults') + + if filters['instance-id'] + instance_ids = filters.delete('instance-id') + instance_ids = [instance_ids] unless instance_ids.is_a?(Array) + instance_ids.each_with_index do |id, index| + params.merge!("InstanceId.#{index}" => id) + end + end + + params['NextToken'] = next_token if next_token + params['MaxResults'] = max_results if max_results + params.merge!(Fog::AWS.indexed_filters(filters)) + + request({ + 'Action' => 'DescribeInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeInstances.new + }.merge!(params)) + end + end + + class Mock + def describe_instances(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_instances with #{filters.class} param is deprecated, use describe_instances('instance-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'instance-id' => [*filters]} + end + + response = Excon::Response.new + + instance_set = self.data[:instances].values + instance_set = apply_tag_filters(instance_set, filters, 'instanceId') + + aliases = { + 'architecture' => 'architecture', + 'availability-zone' => 'availabilityZone', + 'client-token' => 'clientToken', + 'dns-name' => 'dnsName', + 'group-id' => 'groupId', + 'image-id' => 'imageId', + 'instance-id' => 'instanceId', + 'instance-lifecycle' => 'instanceLifecycle', + 'instance-type' => 'instanceType', + 'ip-address' => 'ipAddress', + 'kernel-id' => 'kernelId', + 'key-name' => 'key-name', + 'launch-index' => 'launchIndex', + 'launch-time' => 'launchTime', + 'monitoring-state' => 'monitoringState', + 'owner-id' => 'ownerId', + 'placement-group-name' => 'placementGroupName', + 'platform' => 'platform', + 'private-dns-name' => 'privateDnsName', + 'private-ip-address' => 'privateIpAddress', + 'product-code' => 'productCode', + 'ramdisk-id' => 'ramdiskId', + 'reason' => 'reason', + 'requester-id' => 'requesterId', + 'reservation-id' => 'reservationId', + 'root-device-name' => 'rootDeviceName', + 'root-device-type' => 'rootDeviceType', + 'spot-instance-request-id' => 'spotInstanceRequestId', + 'subnet-id' => 'subnetId', + 'virtualization-type' => 'virtualizationType', + 'vpc-id' => 'vpcId' + } + block_device_mapping_aliases = { + 'attach-time' => 'attachTime', + 'delete-on-termination' => 'deleteOnTermination', + 'device-name' => 'deviceName', + 'status' => 'status', + 'volume-id' => 'volumeId', + } + instance_state_aliases = { + 'code' => 'code', + 'name' => 'name' + } + state_reason_aliases = { + 'code' => 'code', + 'message' => 'message' + } + for filter_key, filter_value in filters + if block_device_mapping_key = filter_key.split('block-device-mapping.')[1] + aliased_key = block_device_mapping_aliases[block_device_mapping_key] + instance_set = instance_set.reject{|instance| !instance['blockDeviceMapping'].find {|block_device_mapping| [*filter_value].include?(block_device_mapping[aliased_key])}} + elsif instance_state_key = filter_key.split('instance-state-')[1] + aliased_key = instance_state_aliases[instance_state_key] + instance_set = instance_set.reject{|instance| ![*filter_value].include?(instance['instanceState'][aliased_key])} + elsif state_reason_key = filter_key.split('state-reason-')[1] + aliased_key = state_reason_aliases[state_reason_key] + instance_set = instance_set.reject{|instance| ![*filter_value].include?(instance['stateReason'][aliased_key])} + elsif filter_key == "availability-zone" + aliased_key = aliases[filter_key] + instance_set = instance_set.reject{|instance| ![*filter_value].include?(instance['placement'][aliased_key])} + elsif filter_key == "group-name" + instance_set = instance_set.reject {|instance| !instance['groupSet'].include?(filter_value)} + elsif filter_key == "group-id" + group_ids = [*filter_value] + security_group_names = self.data[:security_groups].values.select { |sg| group_ids.include?(sg['groupId']) }.map { |sg| sg['groupName'] } + instance_set = instance_set.reject {|instance| (security_group_names & instance['groupSet']).empty?} + else + aliased_key = aliases[filter_key] + instance_set = instance_set.reject {|instance| ![*filter_value].include?(instance[aliased_key])} + end + end + + brand_new_instances = instance_set.select do |instance| + instance['instanceState']['name'] == 'pending' && + Time.now - instance['launchTime'] < Fog::Mock.delay * 2 + end + + # Error if filtering for a brand new instance directly + if (filters['instance-id'] || filters['instanceId']) && !brand_new_instances.empty? + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{brand_new_instances.first['instanceId']}' does not exist") + end + + # Otherwise don't include it in the list + instance_set = instance_set.reject {|instance| brand_new_instances.include?(instance) } + + response.status = 200 + reservation_set = {} + + instance_set.each do |instance| + case instance['instanceState']['name'] + when 'pending' + if Time.now - instance['launchTime'] >= Fog::Mock.delay * 2 + instance['ipAddress'] = Fog::AWS::Mock.ip_address + instance['originalIpAddress'] = instance['ipAddress'] + instance['dnsName'] = Fog::AWS::Mock.dns_name_for(instance['ipAddress']) + instance['instanceState'] = { 'code' => 16, 'name' => 'running' } + end + when 'rebooting' + instance['instanceState'] = { 'code' => 16, 'name' => 'running' } + when 'stopping' + instance['instanceState'] = { 'code' => 0, 'name' => 'stopping' } + instance['stateReason'] = { 'code' => 0 } + when 'shutting-down' + if Time.now - self.data[:deleted_at][instance['instanceId']] >= Fog::Mock.delay * 2 + self.data[:deleted_at].delete(instance['instanceId']) + self.data[:instances].delete(instance['instanceId']) + elsif Time.now - self.data[:deleted_at][instance['instanceId']] >= Fog::Mock.delay + instance['instanceState'] = { 'code' => 48, 'name' => 'terminating' } + end + when 'terminating' + if Time.now - self.data[:deleted_at][instance['instanceId']] >= Fog::Mock.delay + self.data[:deleted_at].delete(instance['instanceId']) + self.data[:instances].delete(instance['instanceId']) + end + end + + if self.data[:instances][instance['instanceId']] + + nics = self.data[:network_interfaces].select{|ni,ni_conf| + ni_conf['attachment']['instanceId'] == instance['instanceId'] + } + instance['networkInterfaces'] = nics.map{|ni,ni_conf| + { + 'ownerId' => ni_conf['ownerId'], + 'subnetId' => ni_conf['subnetId'], + 'vpcId' => ni_conf['vpcId'], + 'networkInterfaceId' => ni_conf['networkInterfaceId'], + 'groupSet' => ni_conf['groupSet'], + 'attachmentId' => ni_conf['attachment']['attachmentId'] + } + } + if nics.count > 0 + + instance['privateIpAddress'] = nics.sort_by {|ni, ni_conf| + ni_conf['attachment']['deviceIndex'] + }.map{ |ni, ni_conf| ni_conf['privateIpAddress'] }.first + + instance['privateDnsName'] = Fog::AWS::Mock.private_dns_name_for(instance['privateIpAddress']) + else + instance['privateIpAddress'] = '' + instance['privateDnsName'] = '' + end + + reservation_set[instance['reservationId']] ||= { + 'groupSet' => instance['groupSet'], + 'groupIds' => instance['groupIds'], + 'instancesSet' => [], + 'ownerId' => instance['ownerId'], + 'reservationId' => instance['reservationId'] + } + reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'ebsOptimized', 'hypervisor', 'iamInstanceProfile', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'networkInterfaces', 'ownerId', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceName', 'rootDeviceType', 'stateReason', 'virtualizationType'].include?(key)}.merge('tagSet' => self.data[:tag_sets][instance['instanceId']]) + end + end + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'reservationSet' => reservation_set.values + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_internet_gateways.rb b/lib/fog/aws/requests/compute/describe_internet_gateways.rb new file mode 100644 index 000000000..fb18e0a3b --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_internet_gateways.rb @@ -0,0 +1,59 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_internet_gateways' + + # Describe all or specified internet_gateways + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'InternetGatewaySet'<~Array>: + # * 'internetGatewayId'<~String> - The ID of the Internet gateway. + # * 'attachmentSet'<~Array>: - A list of VPCs attached to the Internet gateway + # * 'vpcId'<~String> - The ID of the VPC the Internet gateway is attached to + # * 'state'<~String> - The current state of the attachment + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-ItemType-InternetGatewayType.html] + def describe_internet_gateways(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.warning("describe_internet_gateways with #{filters.class} param is deprecated, use internet_gateways('internet-gateway-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'internet-gateway-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeInternetGateways', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeInternetGateways.new + }.merge!(params)) + end + end + + class Mock + def describe_internet_gateways(filters = {}) + internet_gateways = self.data[:internet_gateways].values + + if filters['internet-gateway-id'] + internet_gateways = internet_gateways.reject {|internet_gateway| internet_gateway['internetGatewayId'] != filters['internet-gateway-id']} + end + + Excon::Response.new( + :status => 200, + :body => { + 'requestId' => Fog::AWS::Mock.request_id, + 'internetGatewaySet' => internet_gateways + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_key_pairs.rb b/lib/fog/aws/requests/compute/describe_key_pairs.rb new file mode 100644 index 000000000..a0e75de0d --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_key_pairs.rb @@ -0,0 +1,64 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_key_pairs' + + # Describe all or specified key pairs + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'keySet'<~Array>: + # * 'keyName'<~String> - Name of key + # * 'keyFingerprint'<~String> - Fingerprint of key + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeKeyPairs.html] + def describe_key_pairs(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_key_pairs with #{filters.class} param is deprecated, use describe_key_pairs('key-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'key-name' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeKeyPairs', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeKeyPairs.new + }.merge!(params)) + end + end + + class Mock + def describe_key_pairs(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_key_pairs with #{filters.class} param is deprecated, use describe_key_pairs('key-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'key-name' => [*filters]} + end + + response = Excon::Response.new + + key_set = self.data[:key_pairs].values + + aliases = {'fingerprint' => 'keyFingerprint', 'key-name' => 'keyName'} + for filter_key, filter_value in filters + aliased_key = aliases[filter_key] + key_set = key_set.reject{|key_pair| ![*filter_value].include?(key_pair[aliased_key])} + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'keySet' => key_set.map do |key_pair| + key_pair.reject {|key,value| !['keyFingerprint', 'keyName'].include?(key)} + end + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_network_acls.rb b/lib/fog/aws/requests/compute/describe_network_acls.rb new file mode 100644 index 000000000..a30a1d953 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_network_acls.rb @@ -0,0 +1,108 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_network_acls' + + # Describe all or specified network ACLs + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'networkAclSet'<~Array>: - A list of network ACLs + # * 'networkAclId'<~String> - The ID of the network ACL + # * 'vpcId'<~String> - The ID of the VPC for the network ACL + # * 'default'<~Boolean> - Indicates whether this is the default network ACL for the VPC + # * 'entrySet'<~Array>: - A list of entries (rules) in the network ACL + # * 'ruleNumber'<~Integer> - The rule number for the entry. ACL entries are processed in ascending order by rule number + # * 'protocol'<~Integer> - The protocol. A value of -1 means all protocols + # * 'ruleAction'<~String> - Indicates whether to allow or deny the traffic that matches the rule + # * 'egress'<~Boolean> - Indicates whether the rule is an egress rule (applied to traffic leaving the subnet) + # * 'cidrBlock'<~String> - The network range to allow or deny, in CIDR notation + # * 'icmpTypeCode'<~Hash> - ICMP protocol: The ICMP type and code + # * 'code'<~Integer> - The ICMP code. A value of -1 means all codes for the specified ICMP type + # * 'type'<~Integer> - The ICMP type. A value of -1 means all types + # * 'portRange'<~Hash> - TCP or UDP protocols: The range of ports the rule applies to + # * 'from'<~Integer> - The first port in the range + # * 'to'<~Integer> - The last port in the range + # * 'associationSet'<~Array>: - A list of associations between the network ACL and subnets + # * 'networkAclAssociationId'<~String> - The ID of the association + # * 'networkAclId'<~String> - The ID of the network ACL + # * 'subnetId'<~String> - The ID of the subnet + # * 'tagSet'<~Array>: - Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeNetworkAcls.html] + def describe_network_acls(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeNetworkAcls', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeNetworkAcls.new + }.merge!(params)) + end + end + + class Mock + def describe_network_acls(filters = {}) + response = Excon::Response.new + + network_acls = self.data[:network_acls].values + network_acls = apply_tag_filters(network_acls, filters, 'networkAclId') + + aliases = { + 'vpc-id' => 'vpcId', + 'network-acl-id' => 'networkAclId', + 'default' => 'default', + } + association_aliases = { + 'association-id' => 'networkAclAssociationId', + 'network-acl-id' => 'networkAclId', + 'subnet-id' => 'subnetId', + } + entry_aliases = { + 'cidr' => 'cidrBlock', + 'egress' => 'egress', + 'rule-action' => 'ruleAction', + 'rule-number' => 'ruleNumber', + 'protocol' => 'protocol' + } + for filter_key, filter_value in filters + filter_key = filter_key.to_s + if association_key = filter_key.split('association.')[1] + aliased_key = association_aliases[association_key] + network_acls = network_acls.reject{|nacl| !nacl['associationSet'].find {|association| [*filter_value].include?(association[aliased_key])}} + elsif entry_key = filter_key.split('entry.icmp.')[1] + network_acls = network_acls.reject{|nacl| !nacl['entrySet'].find {|association| [*filter_value].include?(association['icmpTypeCode'][entry_key])}} + elsif entry_key = filter_key.split('entry.port-range.')[1] + network_acls = network_acls.reject{|nacl| !nacl['entrySet'].find {|association| [*filter_value].include?(association['portRange'][entry_key])}} + elsif entry_key = filter_key.split('entry.')[1] + aliased_key = entry_aliases[entry_key] + network_acls = network_acls.reject{|nacl| !nacl['entrySet'].find {|association| [*filter_value].include?(association[aliased_key])}} + else + aliased_key = aliases[filter_key] + network_acls = network_acls.reject{|nacl| ![*filter_value].include?(nacl[aliased_key])} + end + end + + network_acls.each do |acl| + tags = self.data[:tag_sets][acl['networkAclId']] + acl.merge!('tagSet' => tags) if tags + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'networkAclSet' => network_acls + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_network_interface_attribute.rb b/lib/fog/aws/requests/compute/describe_network_interface_attribute.rb new file mode 100644 index 000000000..d23f6ecde --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_network_interface_attribute.rb @@ -0,0 +1,66 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_network_interface_attribute' + # Describes a network interface attribute value + # + # ==== Parameters + # * network_interface_id<~String> - The ID of the network interface you want to describe an attribute of + # * attribute<~String> - The attribute to describe, must be one of 'description', 'groupSet', 'sourceDestCheck' or 'attachment' + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'networkInterfaceId'<~String> - The ID of the network interface + # * 'description'<~String> - The description (if requested) + # * 'groupSet'<~Hash> - Associated security groups (if requested) + # * 'key'<~String> - ID of associated group + # * 'value'<~String> - Name of associated group + # * 'sourceDestCheck'<~Boolean> - Flag indicating whether traffic to or from the instance is validated (if requested) + # * 'attachment'<~Hash>: - Describes the way this nic is attached (if requested) + # * 'attachmentID'<~String> + # * 'instanceID'<~String> + # * 'instanceOwnerId'<~String> + # * 'deviceIndex'<~Integer> + # * 'status'<~String> + # * 'attachTime'<~String> + # * 'deleteOnTermination<~Boolean> + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/ApiReference-query-DescribeNetworkInterfaceAttribute.html] + def describe_network_interface_attribute(network_interface_id, attribute) + request( + 'Action' => 'DescribeNetworkInterfaceAttribute', + 'NetworkInterfaceId' => network_interface_id, + 'Attribute' => attribute, + :parser => Fog::Parsers::Compute::AWS::DescribeNetworkInterfaceAttribute.new + ) + end + end + + class Mock + def describe_network_interface_attribute(network_interface_id, attribute) + response = Excon::Response.new + if self.data[:network_interfaces][network_interface_id] + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'networkInterfaceId' => network_interface_id + } + case attribute + when 'description', 'groupSet', 'sourceDestCheck', 'attachment' + response.body[attribute] = self.data[:network_interfaces][network_interface_id][attribute] + else + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + response + else + raise Fog::Compute::AWS::NotFound.new("The network interface '#{network_interface_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_network_interfaces.rb b/lib/fog/aws/requests/compute/describe_network_interfaces.rb new file mode 100644 index 000000000..4bd25ce4e --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_network_interfaces.rb @@ -0,0 +1,85 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_network_interfaces' + + # Describe all or specified network interfaces + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'networkInterfaceSet'<~Array>: + # * 'networkInterfaceId'<~String> - The ID of the network interface + # * 'subnetId'<~String> - The ID of the subnet + # * 'vpcId'<~String> - The ID of the VPC + # * 'availabilityZone'<~String> - The availability zone + # * 'description'<~String> - The description + # * 'ownerId'<~String> - The ID of the person who created the interface + # * 'requesterId'<~String> - The ID ot teh entity requesting this interface + # * 'requesterManaged'<~String> - + # * 'status'<~String> - "available" or "in-use" + # * 'macAddress'<~String> - + # * 'privateIpAddress'<~String> - IP address of the interface within the subnet + # * 'privateDnsName'<~String> - The private DNS name + # * 'sourceDestCheck'<~Boolean> - Flag indicating whether traffic to or from the instance is validated + # * 'groupSet'<~Hash> - Associated security groups + # * 'key'<~String> - ID of associated group + # * 'value'<~String> - Name of associated group + # * 'attachment'<~Hash>: - Describes the way this nic is attached + # * 'attachmentID'<~String> + # * 'instanceID'<~String> + # * 'instanceOwnerId'<~String> + # * 'deviceIndex'<~Integer> + # * 'status'<~String> + # * 'attachTime'<~String> + # * 'deleteOnTermination'<~Boolean> + # * 'association'<~Hash>: - Describes an eventual instance association + # * 'attachmentID'<~String> - ID of the network interface attachment + # * 'instanceID'<~String> - ID of the instance attached to the network interface + # * 'publicIp'<~String> - Address of the Elastic IP address bound to the network interface + # * 'ipOwnerId'<~String> - ID of the Elastic IP address owner + # * 'tagSet'<~Array>: - Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # * 'privateIpAddresses' <~Array>: + # * 'privateIpAddress'<~String> - One of the additional private ip address + # * 'privateDnsName'<~String> - The private DNS associate to the ip address + # * 'primay'<~String> - Whether main ip associate with NIC true of false + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/index.html?ApiReference-query-DescribeNetworkInterfaces.html] + def describe_network_interfaces(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeNetworkInterfaces', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeNetworkInterfaces.new + }.merge!(params)) + end + end + + class Mock + def describe_network_interfaces(filters = {}) + response = Excon::Response.new + + network_interface_info = self.data[:network_interfaces].values + + for filter_key, filter_value in filters + network_interface_info = network_interface_info.reject{|nic| ![*filter_value].include?(nic[filter_key])} + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'networkInterfaceSet' => network_interface_info + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_placement_groups.rb b/lib/fog/aws/requests/compute/describe_placement_groups.rb new file mode 100644 index 000000000..19c53b67b --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_placement_groups.rb @@ -0,0 +1,33 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_placement_groups' + + # Describe all or specified placement groups + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'placementGroupSet'<~Array>: + # * 'groupName'<~String> - Name of placement group + # * 'strategy'<~String> - Strategy of placement group + # * 'state'<~String> - State of placement group + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribePlacementGroups.html] + def describe_placement_groups(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribePlacementGroups', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribePlacementGroups.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_regions.rb b/lib/fog/aws/requests/compute/describe_regions.rb new file mode 100644 index 000000000..79de5d572 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_regions.rb @@ -0,0 +1,64 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_regions' + + # Describe all or specified regions + # + # ==== Params + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'regionInfo'<~Array>: + # * 'regionName'<~String> - Name of region + # * 'regionEndpoint'<~String> - Service endpoint for region + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeRegions.html] + def describe_regions(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_regions with #{filters.class} param is deprecated, use describe_regions('region-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'region-name' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeRegions', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeRegions.new + }.merge!(params)) + end + end + + class Mock + def describe_regions(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_regions with #{filters.class} param is deprecated, use describe_regions('region-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'region-name' => [*filters]} + end + + response = Excon::Response.new + region_info = [ + {"regionName"=>"eu-west-1", "regionEndpoint"=>"eu-west-1.ec2.amazonaws.com"}, + {"regionName"=>"us-east-1", "regionEndpoint"=>"us-east-1.ec2.amazonaws.com"} + ] + + aliases = {'region-name' => 'regionName', 'endpoint' => 'regionEndpoint'} + for filter_key, filter_value in filters + aliased_key = aliases[filter_key] + region_info = region_info.reject{|region| ![*filter_value].include?(region[aliased_key])} + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'regionInfo' => region_info + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_reserved_instances.rb b/lib/fog/aws/requests/compute/describe_reserved_instances.rb new file mode 100644 index 000000000..1f08de481 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_reserved_instances.rb @@ -0,0 +1,59 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_reserved_instances' + + # Describe all or specified reserved instances + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'reservedInstancesSet'<~Array>: + # * 'availabilityZone'<~String> - availability zone of the instance + # * 'duration'<~Integer> - duration of reservation, in seconds + # * 'fixedPrice'<~Float> - purchase price of reserved instance + # * 'instanceType'<~String> - type of instance + # * 'instanceCount'<~Integer> - number of reserved instances + # * 'productDescription'<~String> - reserved instance description + # * 'reservedInstancesId'<~String> - id of the instance + # * 'start'<~Time> - start time for reservation + # * 'state'<~String> - state of reserved instance purchase, in .[pending-payment, active, payment-failed, retired] + # * 'usagePrice"<~Float> - usage price of reserved instances, per hour + # * 'end' - time reservation stopped being applied (i.e sold or canceled - as of version 2013/10/01) + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeReservedInstances.html] + def describe_reserved_instances(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_reserved_instances with #{filters.class} param is deprecated, use describe_reserved_instances('reserved-instances-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'reserved-instances-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeReservedInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeReservedInstances.new + }.merge!(params)) + end + end + + class Mock + def describe_reserved_instances(filters = {}) + response = Excon::Response.new + response.status = 200 + + response.body = { + 'reservedInstancesSet' => self.data[:reserved_instances].values, + 'requestId' => Fog::AWS::Mock.request_id + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_reserved_instances_offerings.rb b/lib/fog/aws/requests/compute/describe_reserved_instances_offerings.rb new file mode 100644 index 000000000..883e1de27 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_reserved_instances_offerings.rb @@ -0,0 +1,80 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_reserved_instances_offerings' + + # Describe all or specified reserved instances offerings + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # * filters and/or the following + # * 'AvailabilityZone'<~String> - availability zone of offering + # * 'InstanceType'<~String> - instance type of offering + # * 'InstanceTenancy'<~String> - tenancy of offering in ['default', 'dedicated'] + # * 'OfferingType'<~String> - type of offering, in ['Heavy Utilization', 'Medium Utilization', 'Light Utilization'] + # * 'ProductDescription'<~String> - description of offering, in ['Linux/UNIX', 'Linux/UNIX (Amazon VPC)', 'Windows', 'Windows (Amazon VPC)'] + # * 'MaxDuration'<~Integer> - maximum duration (in seconds) of offering + # * 'MinDuration'<~Integer> - minimum duration (in seconds) of offering + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'reservedInstancesOfferingsSet'<~Array>: + # * 'availabilityZone'<~String> - availability zone of offering + # * 'duration'<~Integer> - duration, in seconds, of offering + # * 'fixedPrice'<~Float> - purchase price of offering + # * 'includeMarketplace'<~Boolean> - whether or not to include marketplace offerings + # * 'instanceType'<~String> - instance type of offering + # * 'offeringType'<~String> - type of offering, in ['Heavy Utilization', 'Medium Utilization', 'Light Utilization'] + # * 'productDescription'<~String> - description of offering + # * 'reservedInstancesOfferingId'<~String> - id of offering + # * 'usagePrice'<~Float> - usage price of offering, per hour + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeReservedInstancesOfferings.html] + def describe_reserved_instances_offerings(filters = {}) + options = {} + for key in ['AvailabilityZone', 'InstanceType', 'InstanceTenancy', 'OfferingType', 'ProductDescription', 'MaxDuration', 'MinDuration'] + if filters.is_a?(Hash) && filters.key?(key) + options[key] = filters.delete(key) + end + end + params = Fog::AWS.indexed_filters(filters).merge!(options) + request({ + 'Action' => 'DescribeReservedInstancesOfferings', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeReservedInstancesOfferings.new + }.merge!(params)) + end + end + + class Mock + def describe_reserved_instances_offerings(filters = {}) + response = Excon::Response.new + response.status = 200 + + self.data[:reserved_instances_offerings] ||= [{ + 'reservedInstancesOfferingId' => Fog::AWS::Mock.reserved_instances_offering_id, + 'instanceType' => 'm1.small', + 'availabilityZone' => 'us-east-1d', + 'duration' => 31536000, + 'fixedPrice' => 350.0, + 'offeringType' => 'Medium Utilization', + 'usagePrice' => 0.03, + 'productDescription' => 'Linux/UNIX', + 'instanceTenancy' => 'default', + 'currencyCode' => 'USD' + }] + + response.body = { + 'reservedInstancesOfferingsSet' => self.data[:reserved_instances_offerings], + 'requestId' => Fog::AWS::Mock.request_id + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_route_tables.rb b/lib/fog/aws/requests/compute/describe_route_tables.rb new file mode 100755 index 000000000..3bd393d82 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_route_tables.rb @@ -0,0 +1,86 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_route_tables' + + # Describe one or more of your route tables. + # + # ==== Parameters + # * RouteTableId<~String> - One or more route table IDs. + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - The ID of the request. + # * 'routeTableSet'<~Array>: + # * 'routeTableId'<~String> - The route table's ID. + # * 'vpcId'<~String> - The ID of the VPC for the route table. + # * 'routeSet'<~Array>: + # * 'destinationCidrBlock'<~String> - The CIDR address block used for the destination match. + # * 'gatewayId'<~String> - The ID of a gateway attached to your VPC. + # * 'instanceId'<~String> - The ID of a NAT instance in your VPC. + # * 'instanceOwnerId'<~String> - The owner of the instance. + # * 'networkInterfaceId'<~String> - The network interface ID. + # * 'state'<~String> - The state of the route. The blackhole state indicates that the route's target isn't available. + # * 'origin'<~String> - Describes how the route was created. + # * 'associationSet'<~Array>: + # * 'RouteTableAssociationId'<~String> - An identifier representing the association between a route table and a subnet. + # * 'routeTableId'<~String> - The ID of the route table. + # * 'subnetId'<~String> - The ID of the subnet. + # * 'main'<~Boolean> - Indicates whether this is the main route table. + # * 'propagatingVgwSet'<~Array>: + # * 'gatewayID'<~String> - The ID of the virtual private gateway (VGW). + # * 'tagSet'<~Array>: + # * 'key'<~String> - The tag key. + # * 'value'<~String> - The tag value. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeRouteTables.html] + def describe_route_tables(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_route_tables with #{filters.class} param is deprecated, use describe_route_tables('route-table-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'route-table-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeRouteTables', + :parser => Fog::Parsers::Compute::AWS::DescribeRouteTables.new + }.merge!(params)) + end + end + + class Mock + def describe_route_tables(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_route_tables with #{filters.class} param is deprecated, use describe_route_tables('route-table-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'route-table-id' => [*filters]} + end + + display_routes = self.data[:route_tables].dup + + aliases = { + 'route-table-id' => 'routeTableId', + 'vpc-id' => 'vpcId' + } + + for filter_key, filter_value in filters + filter_attribute = aliases[filter_key] + case filter_attribute + when 'routeTableId', 'vpcId' + display_routes.reject! { |routetable| routetable[filter_attribute] != filter_value } + end + end + + Excon::Response.new( + :status => 200, + :body => { + 'requestId' => Fog::AWS::Mock.request_id, + 'routeTableSet' => display_routes + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_security_groups.rb b/lib/fog/aws/requests/compute/describe_security_groups.rb new file mode 100644 index 000000000..972b0c015 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_security_groups.rb @@ -0,0 +1,98 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_security_groups' + + # Describe all or specified security groups + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'securityGroupInfo'<~Array>: + # * 'groupDescription'<~String> - Description of security group + # * 'groupId'<~String> - ID of the security group. + # * 'groupName'<~String> - Name of security group + # * 'ipPermissions'<~Array>: + # * 'fromPort'<~Integer> - Start of port range (or -1 for ICMP wildcard) + # * 'groups'<~Array>: + # * 'groupName'<~String> - Name of security group + # * 'userId'<~String> - Aws User Id of account + # * 'ipProtocol'<~String> - Ip protocol, must be in ['tcp', 'udp', 'icmp'] + # * 'ipRanges'<~Array>: + # * 'cidrIp'<~String> - CIDR range + # * 'toPort'<~Integer> - End of port range (or -1 for ICMP wildcard) + # * 'ownerId'<~String> - Aws Access Key Id of the owner of the security group + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeSecurityGroups.html] + def describe_security_groups(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_security_groups with #{filters.class} param is deprecated, use describe_security_groups('group-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'group-name' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeSecurityGroups', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeSecurityGroups.new + }.merge!(params)) + end + end + + class Mock + def describe_security_groups(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_security_groups with #{filters.class} param is deprecated, use describe_security_groups('group-name' => []) instead [light_black](#{caller.first})[/]") + filters = {'group-name' => [*filters]} + end + + response = Excon::Response.new + + security_group_info = self.data[:security_groups].reject { |k,v| k['amazon-elb-sg'] }.values + + aliases = { + 'description' => 'groupDescription', + 'group-name' => 'groupName', + 'group-id' => 'groupId', + 'owner-id' => 'ownerId' + } + permission_aliases = { + 'cidr' => 'cidrIp', + 'from-port' => 'fromPort', + 'protocol' => 'ipProtocol', + 'to-port' => 'toPort' + } + security_group_groups = lambda { |security_group| (security_group['ipPermissions'] || []).map { |permission| permission["groups"] }.flatten.compact.uniq } + for filter_key, filter_value in filters + if permission_key = filter_key.split('ip-permission.')[1] + if permission_key == 'group-name' + security_group_info = security_group_info.reject{|security_group| !security_group_groups.call(security_group).find {|group| [*filter_value].include?(group['groupName'])}} + elsif permission_key == 'group-id' + security_group_info = security_group_info.reject{|security_group| !security_group_groups.call(security_group).find {|group| [*filter_value].include?(group['groupId'])}} + elsif permission_key == 'user-id' + security_group_info = security_group_info.reject{|security_group| !security_group_groups.call(security_group).find {|group| [*filter_value].include?(group['userId'])}} + else + aliased_key = permission_aliases[filter_key] + security_group_info = security_group_info.reject{|security_group| !security_group['ipPermissions'].find {|permission| [*filter_value].include?(permission[aliased_key])}} + end + else + aliased_key = aliases[filter_key] + security_group_info = security_group_info.reject{|security_group| ![*filter_value].include?(security_group[aliased_key])} + end + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'securityGroupInfo' => security_group_info + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_snapshots.rb b/lib/fog/aws/requests/compute/describe_snapshots.rb new file mode 100644 index 000000000..ecfdeefc1 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_snapshots.rb @@ -0,0 +1,120 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_snapshots' + + # Describe all or specified snapshots + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # * options<~Hash>: + # * 'Owner'<~String> - Owner of snapshot in ['self', 'amazon', account_id] + # * 'RestorableBy'<~String> - Account id of user who can create volumes from this snapshot + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'snapshotSet'<~Array>: + # * 'encrypted'<~Boolean>: The encryption status of the snapshot. + # * 'progress'<~String>: The percentage progress of the snapshot + # * 'snapshotId'<~String>: Id of the snapshot + # * 'startTime'<~Time>: Timestamp of when snapshot was initiated + # * 'status'<~String>: Snapshot state, in ['pending', 'completed'] + # * 'volumeId'<~String>: Id of volume that snapshot contains + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeSnapshots.html] + def describe_snapshots(filters = {}, options = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_snapshots with #{filters.class} param is deprecated, use describe_snapshots('snapshot-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'snapshot-id' => [*filters]} + end + unless options.empty? + Fog::Logger.deprecation("describe_snapshots with a second param is deprecated, use describe_snapshots(options) instead [light_black](#{caller.first})[/]") + end + + for key in ['ExecutableBy', 'ImageId', 'Owner', 'RestorableBy'] + if filters.key?(key) + options[key] = filters.delete(key) + end + end + options['RestorableBy'] ||= 'self' + params = Fog::AWS.indexed_filters(filters).merge!(options) + request({ + 'Action' => 'DescribeSnapshots', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeSnapshots.new + }.merge!(params)) + end + end + + class Mock + def describe_snapshots(filters = {}, options = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_snapshots with #{filters.class} param is deprecated, use describe_snapshots('snapshot-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'snapshot-id' => [*filters]} + end + unless options.empty? + Fog::Logger.deprecation("describe_snapshots with a second param is deprecated, use describe_snapshots(options) instead [light_black](#{caller.first})[/]") + end + + response = Excon::Response.new + + snapshot_set = self.data[:snapshots].values + + if filters.delete('owner-alias') + Fog::Logger.warning("describe_snapshots with owner-alias is not mocked [light_black](#{caller.first})[/]") + end + if (restorable_by = filters.delete('RestorableBy')) && restorable_by != 'self' + Fog::Logger.warning("describe_snapshots with RestorableBy other than 'self' (wanted #{restorable_by.inspect}) is not mocked [light_black](#{caller.first})[/]") + end + + snapshot_set = apply_tag_filters(snapshot_set, filters, 'snapshotId') + + aliases = { + 'description' => 'description', + 'encrypted' => 'encrypted', + 'owner-id' => 'ownerId', + 'progress' => 'progress', + 'snapshot-id' => 'snapshotId', + 'start-time' => 'startTime', + 'status' => 'status', + 'volume-id' => 'volumeId', + 'volume-size' => 'volumeSize' + } + + for filter_key, filter_value in filters + aliased_key = aliases[filter_key] + snapshot_set = snapshot_set.reject{|snapshot| ![*filter_value].include?(snapshot[aliased_key])} + end + + snapshot_set.each do |snapshot| + case snapshot['status'] + when 'in progress', 'pending' + if Time.now - snapshot['startTime'] >= Fog::Mock.delay * 2 + snapshot['progress'] = '100%' + snapshot['status'] = 'completed' + elsif Time.now - snapshot['startTime'] >= Fog::Mock.delay + snapshot['progress'] = '50%' + snapshot['status'] = 'in progress' + else + snapshot['progress'] = '0%' + snapshot['status'] = 'in progress' + end + end + end + + snapshot_set = snapshot_set.map {|snapshot| snapshot.merge('tagSet' => self.data[:tag_sets][snapshot['snapshotId']]) } + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'snapshotSet' => snapshot_set + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_spot_datafeed_subscription.rb b/lib/fog/aws/requests/compute/describe_spot_datafeed_subscription.rb new file mode 100644 index 000000000..0369b90e9 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_spot_datafeed_subscription.rb @@ -0,0 +1,33 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/spot_datafeed_subscription' + + # Describe spot datafeed subscription + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'spotDatafeedSubscription'<~Hash>: + # * 'bucket'<~String> - S3 bucket where data is stored + # * 'fault'<~Hash>: + # * 'code'<~String> - fault code + # * 'reason'<~String> - fault reason + # * 'ownerId'<~String> - Aws id of account owner + # * 'prefix'<~String> - prefix for datafeed items + # * 'state'<~String> - state of datafeed subscription + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeSpotDatafeedSubscription.html] + def describe_spot_datafeed_subscription + request({ + 'Action' => 'DescribeSpotDatafeedSubscription', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::SpotDatafeedSubscription.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb b/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb new file mode 100644 index 000000000..2ba43b542 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_spot_instance_requests.rb @@ -0,0 +1,46 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/spot_instance_requests' + + # Describe all or specified spot instance requests + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'spotInstanceRequestSet'<~Array>: + # * 'createTime'<~Time> - time of instance request creation + # * 'instanceId'<~String> - instance id if one has been launched to fulfill request + # * 'launchedAvailabilityZone'<~String> - availability zone of instance if one has been launched to fulfill request + # * 'launchSpecification'<~Hash>: + # * 'blockDeviceMapping'<~Hash> - list of block device mappings for instance + # * 'groupSet'<~String> - security group(s) for instance + # * 'keyName'<~String> - keypair name for instance + # * 'imageId'<~String> - AMI for instance + # * 'instanceType'<~String> - type for instance + # * 'monitoring'<~Boolean> - monitoring status for instance + # * 'subnetId'<~String> - VPC subnet ID for instance + # * 'productDescription'<~String> - general description of AMI + # * 'spotInstanceRequestId'<~String> - id of spot instance request + # * 'spotPrice'<~Float> - maximum price for instances to be launched + # * 'state'<~String> - spot instance request state + # * 'type'<~String> - spot instance request type + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeSpotInstanceRequests.html] + def describe_spot_instance_requests(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeSpotInstanceRequests', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::SpotInstanceRequests.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_spot_price_history.rb b/lib/fog/aws/requests/compute/describe_spot_price_history.rb new file mode 100644 index 000000000..0d9665853 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_spot_price_history.rb @@ -0,0 +1,35 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_spot_price_history' + + # Describe all or specified spot price history + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'spotPriceHistorySet'<~Array>: + # * 'availabilityZone'<~String> - availability zone for instance + # * 'instanceType'<~String> - the type of instance + # * 'productDescription'<~String> - general description of AMI + # * 'spotPrice'<~Float> - maximum price to launch one or more instances + # * 'timestamp'<~Time> - date and time of request creation + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeSpotPriceHistory.html] + def describe_spot_price_history(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeSpotPriceHistory', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeSpotPriceHistory.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_subnets.rb b/lib/fog/aws/requests/compute/describe_subnets.rb new file mode 100644 index 000000000..2fa62fb37 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_subnets.rb @@ -0,0 +1,71 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_subnets' + + # Describe all or specified subnets + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'subnetSet'<~Array>: + # * 'subnetId'<~String> - The Subnet's ID + # * 'state'<~String> - The current state of the Subnet. ['pending', 'available'] + # * 'vpcId'<~String> - The ID of the VPC the subnet is in + # * 'cidrBlock'<~String> - The CIDR block the Subnet covers. + # * 'availableIpAddressCount'<~Integer> - The number of unused IP addresses in the subnet (the IP addresses for any + # stopped instances are considered unavailable) + # * 'availabilityZone'<~String> - The Availability Zone the subnet is in. + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # * 'instanceTenancy'<~String> - The allowed tenancy of instances launched into the Subnet. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2011-07-15/APIReference/index.html?ApiReference-query-DescribeSubnets.html] + def describe_subnets(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.warning("describe_subnets with #{filters.class} param is deprecated, use describe_subnets('subnet-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'subnet-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeSubnets', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeSubnets.new + }.merge!(params)) + end + end + + class Mock + def describe_subnets(filters = {}) + subnets = self.data[:subnets] + + # Transition from pending to available + subnets.each do |subnet| + case subnet['state'] + when 'pending' + subnet['state'] = 'available' + end + end + + if filters['subnet-id'] + subnets = subnets.reject {|subnet| subnet['subnetId'] != filters['subnet-id']} + end + + Excon::Response.new( + :status => 200, + :body => { + 'requestId' => Fog::AWS::Mock.request_id, + 'subnetSet' => subnets + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_tags.rb b/lib/fog/aws/requests/compute/describe_tags.rb new file mode 100644 index 000000000..648dd1db5 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_tags.rb @@ -0,0 +1,104 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_tags' + + # Describe all or specified tags + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'tagSet'<~Array>: + # * 'resourceId'<~String> - id of resource tag belongs to + # * 'resourceType'<~String> - type of resource tag belongs to + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeTags.html] + def describe_tags(filters = {}) + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeTags', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeTags.new + }.merge!(params)) + end + end + + class Mock + def describe_tags(filters = {}) + response = Excon::Response.new + + tag_set = deep_clone(self.data[:tags]) + + aliases = { + 'key' => 'key', + 'resource-id' => 'resourceId', + 'resource-type' => 'resourceType', + 'value' => 'value' + } + + for filter_key, filter_value in filters + filter_attribute = aliases[filter_key] + case filter_attribute + when 'key' + tag_set.reject! { |k,_| k != filter_value } + when 'value' + tag_set.each { |k,values| values.reject! { |v, _| v != filter_value } } + when 'resourceId' + filter_resources(tag_set, 'resourceId', filter_value) + when 'resourceType' + filter_resources(tag_set, 'resourceType', filter_value) + end + end + + tagged_resources = [] + tag_set.each do |key, values| + values.each do |value, resources| + resources.each do |resource| + tagged_resources << resource.merge({ + 'key' => key, + 'value' => value + }) + end + end + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'tagSet' => tagged_resources + } + response + end + + private + + def filter_resources(tag_set, filter, value) + value_hash_list = tag_set.values + value_hash_list.each do |value_hash| + value_hash.each do |_, resource_list| + resource_list.reject! { |resource| resource[filter] != value } + end + end + end + + def deep_clone(obj) + case obj + when Hash + obj.reduce({}) { |h, pair| h[pair.first] = deep_clone(pair.last); h } + when Array + obj.map { |o| deep_clone(o) } + else + obj + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_volume_status.rb b/lib/fog/aws/requests/compute/describe_volume_status.rb new file mode 100644 index 000000000..104f6507d --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_volume_status.rb @@ -0,0 +1,43 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_volume_status' + + # http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeVolumeStatus.html + def describe_volume_status(filters = {}) + raise ArgumentError.new("Filters must be a hash, but is a #{filters.class}.") unless filters.is_a?(Hash) + next_token = filters.delete('nextToken') || filters.delete('NextToken') + max_results = filters.delete('maxResults') || filters.delete('MaxResults') + + params = Fog::AWS.indexed_request_param('VolumeId', filters.delete('VolumeId')) + + params.merge!(Fog::AWS.indexed_filters(filters)) + + params['NextToken'] = next_token if next_token + params['MaxResults'] = max_results if max_results + + request({ + 'Action' => 'DescribeVolumeStatus', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeVolumeStatus.new + }.merge!(params)) + end + end + + class Mock + def describe_volume_status(filters = {}) + response = Excon::Response.new + response.status = 200 + + response.body = { + 'volumeStatusSet' => [], + 'requestId' => Fog::AWS::Mock.request_id + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_volumes.rb b/lib/fog/aws/requests/compute/describe_volumes.rb new file mode 100644 index 000000000..f27bd3abc --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_volumes.rb @@ -0,0 +1,118 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_volumes' + + # Describe all or specified volumes. + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'volumeSet'<~Array>: + # * 'availabilityZone'<~String> - Availability zone for volume + # * 'createTime'<~Time> - Timestamp for creation + # * 'encrypted'<~Boolean> - Indicates whether the volume will be encrypted + # * 'iops'<~Integer> - Number of IOPS volume supports + # * 'size'<~Integer> - Size in GiBs for volume + # * 'snapshotId'<~String> - Snapshot volume was created from, if any + # * 'status'<~String> - State of volume + # * 'volumeId'<~String> - Reference to volume + # * 'volumeType'<~String> - Type of volume + # * 'attachmentSet'<~Array>: + # * 'attachmentTime'<~Time> - Timestamp for attachment + # * 'deleteOnTermination'<~Boolean> - Whether or not to delete volume on instance termination + # * 'device'<~String> - How value is exposed to instance + # * 'instanceId'<~String> - Reference to attached instance + # * 'status'<~String> - Attachment state + # * 'volumeId'<~String> - Reference to volume + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DescribeVolumes.html] + def describe_volumes(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_volumes with #{filters.class} param is deprecated, use describe_volumes('volume-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'volume-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeVolumes', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeVolumes.new + }.merge!(params)) + end + end + + class Mock + def describe_volumes(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.deprecation("describe_volumes with #{filters.class} param is deprecated, use describe_volumes('volume-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'volume-id' => [*filters]} + end + + response = Excon::Response.new + + volume_set = self.data[:volumes].values + volume_set = apply_tag_filters(volume_set, filters, 'volumeId') + + aliases = { + 'availability-zone' => 'availabilityZone', + 'create-time' => 'createTime', + 'encrypted' => 'encrypted', + 'size' => 'size', + 'snapshot-id' => 'snapshotId', + 'status' => 'status', + 'volume-id' => 'volumeId' + } + attachment_aliases = { + 'attach-time' => 'attachTime', + 'delete-on-termination' => 'deleteOnTermination', + 'device' => 'device', + 'instance-id' => 'instanceId', + 'status' => 'status' + } + + for filter_key, filter_value in filters + if attachment_key = filter_key.split('attachment.')[1] + aliased_key = attachment_aliases[filter_key] + volume_set = volume_set.reject{|volume| !volume['attachmentSet'].find {|attachment| [*filter_value].include?(attachment[aliased_key])}} + else + aliased_key = aliases[filter_key] + volume_set = volume_set.reject{|volume| ![*filter_value].include?(volume[aliased_key])} + end + end + + volume_set.each do |volume| + case volume['status'] + when 'attaching' + if Time.now - volume['attachmentSet'].first['attachTime'] >= Fog::Mock.delay + volume['attachmentSet'].first['status'] = 'in-use' + volume['status'] = 'in-use' + end + when 'creating' + if Time.now - volume['createTime'] >= Fog::Mock.delay + volume['status'] = 'available' + end + when 'deleting' + if Time.now - self.data[:deleted_at][volume['volumeId']] >= Fog::Mock.delay + self.data[:deleted_at].delete(volume['volumeId']) + self.data[:volumes].delete(volume['volumeId']) + end + end + end + volume_set = volume_set.reject {|volume| !self.data[:volumes][volume['volumeId']]} + volume_set = volume_set.map {|volume| volume.merge('tagSet' => self.data[:tag_sets][volume['volumeId']]) } + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'volumeSet' => volume_set + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_vpc_attribute.rb b/lib/fog/aws/requests/compute/describe_vpc_attribute.rb new file mode 100644 index 000000000..45f42e8f4 --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_vpc_attribute.rb @@ -0,0 +1,55 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_vpc_attribute' + # Describes a vpc attribute value + # + # ==== Parameters + # * vpc_id<~String> - The ID of the VPC you want to describe an attribute of + # * attribute<~String> - The attribute to describe, must be one of 'enableDnsSupport' or 'enableDnsHostnames' + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'vpcId'<~String> - The ID of the VPC + # * 'enableDnsSupport'<~Boolean> - Flag indicating whether DNS resolution is enabled for the VPC (if requested) + # * 'enableDnsHostnames'<~Boolean> - Flag indicating whether the instances launched in the VPC get DNS hostnames (if requested) + # + # (Amazon API Reference)[http://docs.amazonwebservices.com/AwsEC2/2014-02-01/APIReference/ApiReference-query-DescribeVpcAttribute.html] + def describe_vpc_attribute(vpc_id, attribute) + request( + 'Action' => 'DescribeVpcAttribute', + 'VpcId' => vpc_id, + 'Attribute' => attribute, + :parser => Fog::Parsers::Compute::AWS::DescribeVpcAttribute.new + ) + end + end + + class Mock + def describe_vpc_attribute(vpc_id, attribute) + response = Excon::Response.new + if vpc = self.data[:vpcs].find{ |v| v['vpcId'] == vpc_id } + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'vpcId' => vpc_id + } + + case attribute + when 'enableDnsSupport', 'enableDnsHostnames' + response.body[attribute] = vpc[attribute] + else + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + response + else + raise Fog::Compute::AWS::NotFound.new("The VPC '#{vpc_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/describe_vpcs.rb b/lib/fog/aws/requests/compute/describe_vpcs.rb new file mode 100644 index 000000000..dfce9d32c --- /dev/null +++ b/lib/fog/aws/requests/compute/describe_vpcs.rb @@ -0,0 +1,74 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/describe_vpcs' + + # Describe all or specified vpcs + # + # ==== Parameters + # * filters<~Hash> - List of filters to limit results with + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'vpcSet'<~Array>: + # * 'vpcId'<~String> - The VPC's ID + # * 'state'<~String> - The current state of the VPC. ['pending', 'available'] + # * 'cidrBlock'<~String> - The CIDR block the VPC covers. + # * 'dhcpOptionsId'<~String> - The ID of the set of DHCP options. + # * 'tagSet'<~Array>: Tags assigned to the resource. + # * 'key'<~String> - Tag's key + # * 'value'<~String> - Tag's value + # * 'instanceTenancy'<~String> - The allowed tenancy of instances launched into the VPC. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2011-07-15/APIReference/index.html?ApiReference-query-DescribeVpcs.html] + def describe_vpcs(filters = {}) + unless filters.is_a?(Hash) + Fog::Logger.warning("describe_vpcs with #{filters.class} param is deprecated, use describe_vpcs('vpc-id' => []) instead [light_black](#{caller.first})[/]") + filters = {'vpc-id' => [*filters]} + end + params = Fog::AWS.indexed_filters(filters) + request({ + 'Action' => 'DescribeVpcs', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DescribeVpcs.new + }.merge!(params)) + end + end + + class Mock + def describe_vpcs(filters = {}) + vpcs = self.data[:vpcs] + vpcs = apply_tag_filters(vpcs, filters, 'vpcId') + + # Transition from pending to available + vpcs.each do |vpc| + case vpc['state'] + when 'pending' + vpc['state'] = 'available' + end + end + + if filters['vpc-id'] + vpcs = vpcs.reject {|vpc| vpc['vpcId'] != filters['vpc-id']} + end + + vpcs.each do |vpc| + tags = self.data[:tag_sets][vpc['vpcId']] + vpc.merge!('tagSet' => tags) if tags + end + + Excon::Response.new( + :status => 200, + :body => { + 'requestId' => Fog::AWS::Mock.request_id, + 'vpcSet' => vpcs + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/detach_internet_gateway.rb b/lib/fog/aws/requests/compute/detach_internet_gateway.rb new file mode 100644 index 000000000..985705f40 --- /dev/null +++ b/lib/fog/aws/requests/compute/detach_internet_gateway.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + # Detaches an Internet gateway to a VPC, enabling connectivity between the Internet and the VPC + # + # ==== Parameters + # * internet_gateway_id<~String> - The ID of the Internet gateway to detach + # * vpc_id<~String> - The ID of the VPC + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DetachInternetGateway.html] + def detach_internet_gateway(internet_gateway_id, vpc_id) + request( + 'Action' => 'DetachInternetGateway', + 'InternetGatewayId' => internet_gateway_id, + 'VpcId' => vpc_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def detach_internet_gateway(internet_gateway_id, vpc_id) + response = Excon::Response.new + if internet_gateway_id && vpc_id + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + if !internet_gateway_id + message << 'The request must contain the parameter internet_gateway_id' + elsif !vpc_id + message << 'The request must contain the parameter vpc_id' + end + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/detach_network_interface.rb b/lib/fog/aws/requests/compute/detach_network_interface.rb new file mode 100644 index 000000000..d56c3faa4 --- /dev/null +++ b/lib/fog/aws/requests/compute/detach_network_interface.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + # Detaches a network interface. + # + # ==== Parameters + # * attachment_id<~String> - ID of the attachment to detach + # * force<~Boolean> - Set to true to force a detachment + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/ApiReference-query-DetachNetworkInterface.html] + def detach_network_interface(attachment_id, force = false) + request( + 'Action' => 'DetachNetworkInterface', + 'AttachmentId' => attachment_id, + 'Force' => force, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def detach_network_interface(attachment_id, force = false) + response = Excon::Response.new + nic_id = self.data[:network_interfaces].select { |k,v| v['attachment']['attachmentId'] == attachment_id} .first.first + if nic_id + self.data[:network_interfaces][nic_id]["attachment"] = {} + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network interface '#{network_interface_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/detach_volume.rb b/lib/fog/aws/requests/compute/detach_volume.rb new file mode 100644 index 000000000..dd7827db2 --- /dev/null +++ b/lib/fog/aws/requests/compute/detach_volume.rb @@ -0,0 +1,61 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/detach_volume' + + # Detach an Amazon EBS volume from a running instance + # + # ==== Parameters + # * volume_id<~String> - Id of amazon EBS volume to associate with instance + # * options<~Hash>: + # * 'Device'<~String> - Specifies how the device is exposed to the instance (e.g. "/dev/sdh") + # * 'Force'<~Boolean> - If true forces detach, can cause data loss/corruption + # * 'InstanceId'<~String> - Id of instance to associate volume with + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'attachTime'<~Time> - Time of attachment was initiated at + # * 'device'<~String> - Device as it is exposed to the instance + # * 'instanceId'<~String> - Id of instance for volume + # * 'requestId'<~String> - Id of request + # * 'status'<~String> - Status of volume + # * 'volumeId'<~String> - Reference to volume + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DetachVolume.html] + def detach_volume(volume_id, options = {}) + request({ + 'Action' => 'DetachVolume', + 'VolumeId' => volume_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::DetachVolume.new + }.merge!(options)) + end + end + + class Mock + def detach_volume(volume_id, options = {}) + response = Excon::Response.new + response.status = 200 + if (volume = self.data[:volumes][volume_id]) + if !volume['attachmentSet'].empty? + data = volume['attachmentSet'].pop + volume['status'] = 'available' + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + response + else + # real response has spacing issue below + raise Fog::Compute::AWS::Error.new("IncorrectState => Volume '#{volume_id}'is in the 'available' state.") + end + else + raise Fog::Compute::AWS::NotFound.new("The volume '#{volume_id}' does not exist.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/disassociate_address.rb b/lib/fog/aws/requests/compute/disassociate_address.rb new file mode 100644 index 000000000..2128c3345 --- /dev/null +++ b/lib/fog/aws/requests/compute/disassociate_address.rb @@ -0,0 +1,55 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Disassociate an elastic IP address from its instance (if any) + # + # ==== Parameters + # * public_ip<~String> - Public ip to assign to instance + # * association_id<~String> - Id associating eip to an network interface + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-DisassociateAddress.html] + def disassociate_address(public_ip=nil, association_id=nil) + request( + 'Action' => 'DisassociateAddress', + 'PublicIp' => public_ip, + 'AssociationId' => association_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def disassociate_address(public_ip) + response = Excon::Response.new + response.status = 200 + if address = self.data[:addresses][public_ip] + instance_id = address['instanceId'] + if instance = self.data[:instances][instance_id] + instance['ipAddress'] = instance['originalIpAddress'] + instance['dnsName'] = Fog::AWS::Mock.dns_name_for(instance['ipAddress']) + end + address['instanceId'] = nil + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::Error.new("AuthFailure => The address '#{public_ip}' does not belong to you.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/disassociate_route_table.rb b/lib/fog/aws/requests/compute/disassociate_route_table.rb new file mode 100755 index 000000000..1da4c9e0f --- /dev/null +++ b/lib/fog/aws/requests/compute/disassociate_route_table.rb @@ -0,0 +1,54 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Disassociates a subnet from a route table. + # + # ==== Parameters + # * AssociationId<~String> - The association ID representing the current association between the route table and subnet. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - The ID of the request. + # * 'return'<~Boolean> - Returns true if the request succeeds. Otherwise, returns an error. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-DisassociateRouteTable.html] + def disassociate_route_table(association_id) + request( + 'Action' => 'DisassociateRouteTable', + 'AssociationId' => association_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def disassociate_route_table(association_id) + assoc_array = nil + routetable = self.data[:route_tables].find { |routetable| + assoc_array = routetable["associationSet"].find { |association| + association['routeTableAssociationId'].eql? association_id + } + } + if !assoc_array.nil? && assoc_array['main'] == false + routetable['associationSet'].delete(assoc_array) + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + elsif assoc_array.nil? + raise Fog::Compute::AWS::NotFound.new("The association ID '#{association_id}' does not exist") + elsif assoc_array['main'] == true + raise Fog::Compute::AWS::Error, "InvalidParameterValue => cannot disassociate the main route table association #{association_id}" + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/get_console_output.rb b/lib/fog/aws/requests/compute/get_console_output.rb new file mode 100644 index 000000000..7ca482acf --- /dev/null +++ b/lib/fog/aws/requests/compute/get_console_output.rb @@ -0,0 +1,50 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/get_console_output' + + # Retrieve console output for specified instance + # + # ==== Parameters + # * instance_id<~String> - Id of instance to get console output from + # + # ==== Returns + # # * response<~Excon::Response>: + # * body<~Hash>: + # * 'instanceId'<~String> - Id of instance + # * 'output'<~String> - Console output + # * 'requestId'<~String> - Id of request + # * 'timestamp'<~Time> - Timestamp of last update to output + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-GetConsoleOutput.html] + def get_console_output(instance_id) + request( + 'Action' => 'GetConsoleOutput', + 'InstanceId' => instance_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::GetConsoleOutput.new + ) + end + end + + class Mock + def get_console_output(instance_id) + response = Excon::Response.new + if instance = self.data[:instances][instance_id] + response.status = 200 + response.body = { + 'instanceId' => instance_id, + 'output' => (Time.now - instance['launchTime'] >= Fog::Mock.delay) ? nil : Fog::AWS::Mock.console_output, + 'requestId' => Fog::AWS::Mock.request_id, + 'timestamp' => Time.now + } + response + else; + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/get_password_data.rb b/lib/fog/aws/requests/compute/get_password_data.rb new file mode 100644 index 000000000..df7d0e5cc --- /dev/null +++ b/lib/fog/aws/requests/compute/get_password_data.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/get_password_data' + + # Retrieves the encrypted administrator password for an instance running Windows. + # + # ==== Parameters + # * instance_id<~String> - A Windows instance ID + # + # ==== Returns + # # * response<~Excon::Response>: + # * body<~Hash>: + # * 'instanceId'<~String> - Id of instance + # * 'passwordData'<~String> - The encrypted, base64-encoded password of the instance. + # * 'requestId'<~String> - Id of request + # * 'timestamp'<~Time> - Timestamp of last update to output + # + # See http://docs.amazonwebservices.com/AwsEC2/2010-08-31/APIReference/index.html?ApiReference-query-GetPasswordData.html + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-GetPasswordData.html] + def get_password_data(instance_id) + request( + 'Action' => 'GetPasswordData', + 'InstanceId' => instance_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::GetPasswordData.new + ) + end + end + + class Mock + def get_password_data(instance_id) + response = Excon::Response.new + if instance = self.data[:instances][instance_id] + response.status = 200 + response.body = { + 'instanceId' => instance_id, + 'passwordData' => nil, + 'requestId' => Fog::AWS::Mock.request_id, + 'timestamp' => Time.now + } + response + else; + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/import_key_pair.rb b/lib/fog/aws/requests/compute/import_key_pair.rb new file mode 100644 index 000000000..fb2ba3d97 --- /dev/null +++ b/lib/fog/aws/requests/compute/import_key_pair.rb @@ -0,0 +1,52 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/import_key_pair' + + # Import an existing public key to create a new key pair + # + # ==== Parameters + # * key_name<~String> - Unique name for key pair. + # * public_key_material<~String> - RSA public key + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'keyFingerprint'<~String> - SHA-1 digest of DER encoded private key + # * 'keyName'<~String> - Name of key + # * 'requestId'<~String> - Id of request + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-ImportKeyPair.html] + def import_key_pair(key_name, public_key_material) + request( + 'Action' => 'ImportKeyPair', + 'KeyName' => key_name, + 'PublicKeyMaterial' => Base64::encode64(public_key_material), + :parser => Fog::Parsers::Compute::AWS::ImportKeyPair.new + ) + end + end + + class Mock + def import_key_pair(key_name, public_key_material) + response = Excon::Response.new + unless self.data[:key_pairs][key_name] + response.status = 200 + data = { + 'keyFingerprint' => Fog::AWS::Mock.key_fingerprint, + 'keyName' => key_name + } + self.data[:key_pairs][key_name] = data + response.body = { + 'requestId' => Fog::AWS::Mock.request_id + }.merge!(data) + response + else + raise Fog::Compute::AWS::Error.new("InvalidKeyPair.Duplicate => The keypair '#{key_name}' already exists.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_image_attribute.rb b/lib/fog/aws/requests/compute/modify_image_attribute.rb new file mode 100644 index 000000000..9ce9d3629 --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_image_attribute.rb @@ -0,0 +1,70 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Modify image attributes + # + # ==== Parameters + # * image_id<~String> - Id of machine image to modify + # * attributes<~Hash>: + # * 'Add.Group'<~Array> - One or more groups to grant launch permission to + # * 'Add.UserId'<~Array> - One or more account ids to grant launch permission to + # * 'Description.Value' - New description for image + # * 'ProductCode'<~Array> - One or more product codes to add to image (these can not be removed) + # * 'Remove.Group'<~Array> - One or more groups to revoke launch permission from + # * 'Remove.UserId'<~Array> - One or more account ids to revoke launch permission from + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-ModifyImageAttribute.html] + # + def modify_image_attribute(image_id, attributes) + raise ArgumentError.new("image_id is required") unless image_id + + params = {} + params.merge!(Fog::AWS.indexed_param('LaunchPermission.Add.%d.Group', attributes['Add.Group'] || [])) + params.merge!(Fog::AWS.indexed_param('LaunchPermission.Add.%d.UserId', attributes['Add.UserId'] || [])) + params.merge!(Fog::AWS.indexed_param('LaunchPermission.Remove.%d.Group', attributes['Remove.Group'] || [])) + params.merge!(Fog::AWS.indexed_param('LaunchPermission.Remove.%d.UserId', attributes['Remove.UserId'] || [])) + params.merge!(Fog::AWS.indexed_param('ProductCode', attributes['ProductCode'] || [])) + request({ + 'Action' => 'ModifyImageAttribute', + 'ImageId' => image_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + end + + class Mock + def modify_image_attribute(image_id, attributes) + raise ArgumentError.new("image_id is required") unless image_id + + unless self.data[:images][image_id] + raise Fog::Compute::AWS::NotFound.new("The AMI ID '#{image_id}' does not exist") + end + + (attributes['Add.UserId'] || []).each do |user_id| + if image_launch_permissions = self.data[:image_launch_permissions][image_id] + image_launch_permissions[:users].push(user_id) + end + end + + (attributes['Remove.UserId'] || []).each do |user_id| + if image_launch_permissions = self.data[:image_launch_permissions][image_id] + image_launch_permissions[:users].delete(user_id) + end + end + + response = Excon::Response.new + response.status = 200 + response.body = { + 'return' => true, + 'requestId' => Fog::AWS::Mock.request_id + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_instance_attribute.rb b/lib/fog/aws/requests/compute/modify_instance_attribute.rb new file mode 100644 index 000000000..389769fd0 --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_instance_attribute.rb @@ -0,0 +1,42 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Modify instance attributes + # + # ==== Parameters + # * instance_id<~String> - Id of instance to modify + # * attributes<~Hash>: + # 'InstanceType.Value'<~String> - New instance type + # 'Kernel.Value'<~String> - New kernel value + # 'Ramdisk.Value'<~String> - New ramdisk value + # 'UserData.Value'<~String> - New userdata value + # 'DisableApiTermination.Value'<~Boolean> - Change api termination value + # 'InstanceInitiatedShutdownBehavior.Value'<~String> - New instance initiated shutdown behaviour, in ['stop', 'terminate'] + # 'SourceDestCheck.Value'<~Boolean> - New sourcedestcheck value + # 'GroupId'<~Array> - One or more groups to add instance to (VPC only) + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-ModifyInstanceAttribute.html] + # + def modify_instance_attribute(instance_id, attributes) + params = {} + params.merge!(Fog::AWS.indexed_param('GroupId', attributes.delete('GroupId') || [])) + params.merge!(attributes) + request({ + 'Action' => 'ModifyInstanceAttribute', + 'InstanceId' => instance_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + + def modify_instance_attributes(instance_id, attributes) + Fog::Logger.deprecation("modify_instance_attributes method is deprecated, use 'modify_instance_attribute' instead") + modify_instance_attribute(instance_id, attributes) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_network_interface_attribute.rb b/lib/fog/aws/requests/compute/modify_network_interface_attribute.rb new file mode 100644 index 000000000..0cc6a4f4a --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_network_interface_attribute.rb @@ -0,0 +1,89 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Modifies a network interface attribute value + # + # ==== Parameters + # * network_interface_id<~String> - The ID of the network interface you want to describe an attribute of + # * attribute<~String> - The attribute to modify, must be one of 'description', 'groupSet', 'sourceDestCheck' or 'attachment' + # * value<~Object> - New value of attribute, the actual tyep depends on teh attribute: + # description - a string + # groupSet - a list of group id's + # sourceDestCheck - a boolean value + # attachment - a hash with: + # attachmentid - the attachment to change + # deleteOnTermination - a boolean + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/ApiReference-query-ModifyNetworkInterfaceAttribute.html] + def modify_network_interface_attribute(network_interface_id, attribute, value) + params = {} + case attribute + when 'description' + params['Description.Value'] = value + when 'groupSet' + params.merge!(Fog::AWS.indexed_param('SecurityGroupId.%d', value)) + when 'sourceDestCheck' + params['SourceDestCheck.Value'] = value + when 'attachment' + params['Attachment.AttachmentId'] = value['attachmentId'] + params['Attachment.DeleteOnTermination'] = value['deleteOnTermination'] + else + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + + request({ + 'Action' => 'ModifyNetworkInterfaceAttribute', + 'NetworkInterfaceId' => network_interface_id, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + end + + class Mock + def modify_network_interface_attribute(network_interface_id, attribute, value) + response = Excon::Response.new + if self.data[:network_interfaces][network_interface_id] + nic = self.data[:network_interfaces][network_interface_id] + + case attribute + when 'description' + nic['description'] = value.clone + when 'groupSet' + groups = {} + value.each do |group_id| + name = self.data[:security_groups].select { |k,v| v['groupId'] == group_id } .first.first + if name.nil? + raise Fog::Compute::AWS::Error.new("Unknown security group '#{group_id}' specified") + end + groups[group_id] = name + end + nic['groupSet'] = groups + when 'sourceDestCheck' + nic['sourceDestCheck'] = value + when 'attachment' + if nic['attachment'].nil? || value['attachmentId'] != nic['attachment']['attachmentId'] + raise Fog::Compute::AWS::Error.new("Illegal attachment '#{value['attachmentId']}' specified") + end + nic['attachment']['deleteOnTermination'] = value['deleteOnTermination'] + else + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + + response + else + raise Fog::Compute::AWS::NotFound.new("The network interface '#{network_interface_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_snapshot_attribute.rb b/lib/fog/aws/requests/compute/modify_snapshot_attribute.rb new file mode 100644 index 000000000..11b5a4251 --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_snapshot_attribute.rb @@ -0,0 +1,35 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Modify snapshot attributes + # + # ==== Parameters + # * snapshot_id<~String> - Id of snapshot to modify + # * attributes<~Hash>: + # * 'Add.Group'<~Array> - One or more groups to grant volume create permission to + # * 'Add.UserId'<~Array> - One or more account ids to grant volume create permission to + # * 'Remove.Group'<~Array> - One or more groups to revoke volume create permission from + # * 'Remove.UserId'<~Array> - One or more account ids to revoke volume create permission from + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-ModifySnapshotAttribute.html] + # + def modify_snapshot_attribute(snapshot_id, attributes) + params = {} + params.merge!(Fog::AWS.indexed_param('CreateVolumePermission.Add.%d.Group', attributes['Add.Group'] || [])) + params.merge!(Fog::AWS.indexed_param('CreateVolumePermission.Add.%d.UserId', attributes['Add.UserId'] || [])) + params.merge!(Fog::AWS.indexed_param('CreateVolumePermission.Remove.%d.Group', attributes['Remove.Group'] || [])) + params.merge!(Fog::AWS.indexed_param('CreateVolumePermission.Remove.%d.UserId', attributes['Remove.UserId'] || [])) + request({ + 'Action' => 'ModifySnapshotAttribute', + 'SnapshotId' => snapshot_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_subnet_attribute.rb b/lib/fog/aws/requests/compute/modify_subnet_attribute.rb new file mode 100644 index 000000000..dd75d61ee --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_subnet_attribute.rb @@ -0,0 +1,58 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/modify_subnet_attribute' + + # Modifies a subnet attribute. + # + # ==== Parameters + # * SubnetId<~String> - The id of the subnet to modify + # * options<~Hash>: + # * MapPublicIpOnLaunch<~Boolean> - Modifies the public IP addressing behavior for the subnet. + # Specify true to indicate that instances launched into the specified subnet should be assigned a public IP address. + # If set to true, the instance receives a public IP address only if the instance is launched with a single, + # new network interface with the device index of 0. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. Otherwise, returns an error. + # http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-ModifySubnetAttribute.html + def modify_subnet_attribute(subnet_id, options = {}) + params = {} + params['MapPublicIpOnLaunch.Value'] = options.delete 'MapPublicIpOnLaunch' if options['MapPublicIpOnLaunch'] + request({ + 'Action' => 'ModifySubnetAttribute', + 'SubnetId' => subnet_id, + :parser => Fog::Parsers::Compute::AWS::ModifySubnetAttribute.new + }.merge(params)) + end + end + + class Mock + def modify_subnet_attribute(subnet_id, options={}) + Excon::Response.new.tap do |response| + subnet = self.data[:subnets].detect { |v| v['subnetId'] == subnet_id } + if subnet + subnet['mapPublicIpOnLaunch'] = options['MapPublicIpOnLaunch'] + + response.status = 200 + + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + else + response.status = 404 + response.body = { + 'Code' => 'InvalidParameterValue' + } + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_volume_attribute.rb b/lib/fog/aws/requests/compute/modify_volume_attribute.rb new file mode 100644 index 000000000..27a358e43 --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_volume_attribute.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Modifies a volume attribute. + # + # ==== Parameters + # * volume_id<~String> - The ID of the volume. + # * auto_enable_io_value<~Boolean> - This attribute exists to auto-enable the I/O operations to the volume. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-ModifyVolumeAttribute.html] + def modify_volume_attribute(volume_id=nil, auto_enable_io_value=false) + request( + 'Action' => 'ModifyVolumeAttribute', + 'VolumeId' => volume_id, + 'AutoEnableIO.Value' => auto_enable_io_value, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def modify_volume_attribute(volume_id=nil, auto_enable_io_value=false) + response = Excon::Response.new + if volume = self.data[:volumes][volume_id] + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The volume '#{volume_id}' does not exist.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/modify_vpc_attribute.rb b/lib/fog/aws/requests/compute/modify_vpc_attribute.rb new file mode 100644 index 000000000..a5bdd42ab --- /dev/null +++ b/lib/fog/aws/requests/compute/modify_vpc_attribute.rb @@ -0,0 +1,66 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Modifies the specified attribute of the specified VPC. + # + # ==== Parameters + # * vpc_id<~String> - The ID of the VPC. + # * options<~Hash>: + # * enableDnsSupport<~Boolean> - Indicates whether DNS resolution is supported for the VPC. If this attribute is true, the Amazon DNS + # server resolves DNS hostnames for your instances to their corresponding IP addresses; otherwise, it does not. + # * enableDnsHostnames<~Boolean> - Indicates whether the instances launched in the VPC get DNS hostnames. If this attribute is true, + # instances in the VPC get DNS hostnames; otherwise, they do not. You can only set enableDnsHostnames to true if you also set the + # EnableDnsSupport attribute to true. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-ModifyVpcAttribute.html] + def modify_vpc_attribute(vpc_id, options = {}) + request({ + 'Action' => 'ModifyVpcAttribute', + 'VpcId' => vpc_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(options)) + end + end + + class Mock + def modify_vpc_attribute(vpc_id, options = {}) + response = Excon::Response.new + if options.size == 0 + raise Fog::Compute::AWS::Error.new("InvalidParameterCombination => No attributes specified.") + elsif options.size > 1 + raise Fog::Compute::AWS::Error.new("InvalidParameterCombination => InvalidParameterCombination => Fields for multiple attribute types specified: #{options.keys.join(', ')}") + elsif vpc = self.data[:vpcs].find{ |v| v['vpcId'] == vpc_id } + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + + attribute = options.keys.first + case attribute + when 'EnableDnsSupport.Value' + vpc['enableDnsSupport'] = options[attribute] + when 'EnableDnsHostnames.Value' + vpc['enableDnsHostnames'] = options[attribute] + else + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + response + else + raise Fog::Compute::AWS::NotFound.new("The VPC '#{vpc_id}' does not exist.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/monitor_instances.rb b/lib/fog/aws/requests/compute/monitor_instances.rb new file mode 100644 index 000000000..07a0785e6 --- /dev/null +++ b/lib/fog/aws/requests/compute/monitor_instances.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/monitor_unmonitor_instances' + + # Monitor specified instance + # http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-MonitorInstances.html + # + # ==== Parameters + # * instance_ids<~Array> - Arrays of instances Ids to monitor + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'instancesSet': http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-ItemType-MonitorInstancesResponseSetItemType.html + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-MonitorInstances.html] + def monitor_instances(instance_ids) + params = Fog::AWS.indexed_param('InstanceId', instance_ids) + request({ + 'Action' => 'MonitorInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::MonitorUnmonitorInstances.new + }.merge!(params)) + end + end + + class Mock + def monitor_instances(instance_ids) + response = Excon::Response.new + response.status = 200 + [*instance_ids].each do |instance_id| + if instance = self.data[:instances][instance_id] + instance['monitoring']['state'] = 'enabled' + else + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_ids}' does not exist") + end + end + instances_set = [*instance_ids].reduce([]) { |memo, id| memo << {'instanceId' => id, 'monitoring' => 'enabled'} } + response.body = {'requestId' => 'some_request_id', 'instancesSet' => instances_set} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/purchase_reserved_instances_offering.rb b/lib/fog/aws/requests/compute/purchase_reserved_instances_offering.rb new file mode 100644 index 000000000..c0da97364 --- /dev/null +++ b/lib/fog/aws/requests/compute/purchase_reserved_instances_offering.rb @@ -0,0 +1,62 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/purchase_reserved_instances_offering' + + # Purchases a Reserved Instance for use with your account. + # + # ==== Parameters + # * reserved_instances_offering_id<~String> - ID of the Reserved Instance offering you want to purchase. + # * instance_count<~Integer> - The number of Reserved Instances to purchase. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'reservedInstancesId'<~String> - Id of the purchased reserved instances. + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-PurchaseReservedInstancesOffering.html] + def purchase_reserved_instances_offering(reserved_instances_offering_id, instance_count = 1) + request({ + 'Action' => 'PurchaseReservedInstancesOffering', + 'ReservedInstancesOfferingId' => reserved_instances_offering_id, + 'InstanceCount' => instance_count, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::PurchaseReservedInstancesOffering.new + }) + end + end + + class Mock + def purchase_reserved_instances_offering(reserved_instances_offering_id, instance_count = 1) + response = Excon::Response.new + response.status = 200 + + # Need to implement filters in the mock to find this there instead of here + # Also there's no information about what to do when the specified reserved_instances_offering_id doesn't exist + raise unless reserved_instance_offering = describe_reserved_instances_offerings.body["reservedInstancesOfferingsSet"].find { |offering| offering["reservedInstancesOfferingId"] == reserved_instances_offering_id } + + reserved_instances_id = Fog::AWS::Mock.reserved_instances_id + reserved_instance_offering.delete('reservedInstancesOfferingId') + + self.data[:reserved_instances][reserved_instances_id] = reserved_instance_offering.merge({ + 'reservedInstancesId' => reserved_instances_id, + 'start' => Time.now, + 'end' => Time.now, + 'instanceCount' => instance_count, + 'state' => 'payment-pending', + 'tagSet' => [] + }) + + response.body = { + 'reservedInstancesId' => reserved_instances_id, + 'requestId' => Fog::AWS::Mock.request_id + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/reboot_instances.rb b/lib/fog/aws/requests/compute/reboot_instances.rb new file mode 100644 index 000000000..658454219 --- /dev/null +++ b/lib/fog/aws/requests/compute/reboot_instances.rb @@ -0,0 +1,50 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Reboot specified instances + # + # ==== Parameters + # * instance_id<~Array> - Ids of instances to reboot + # + # ==== Returns + # # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-RebootInstances.html] + def reboot_instances(instance_id = []) + params = Fog::AWS.indexed_param('InstanceId', instance_id) + request({ + 'Action' => 'RebootInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(params)) + end + end + + class Mock + def reboot_instances(instance_id = []) + response = Excon::Response.new + instance_id = [*instance_id] + if (self.data[:instances].keys & instance_id).length == instance_id.length + for instance_id in instance_id + self.data[:instances][instance_id]['status'] = 'rebooting' + end + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The instance ID #{instance_id.inspect} does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/register_image.rb b/lib/fog/aws/requests/compute/register_image.rb new file mode 100644 index 000000000..51eecff7d --- /dev/null +++ b/lib/fog/aws/requests/compute/register_image.rb @@ -0,0 +1,133 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/register_image' + + # register an image + # + # ==== Parameters + # * Name<~String> - Name of the AMI to be registered + # * Description<~String> - AMI description + # * Location<~String> - S3 manifest location (for S3 backed AMIs) + # or + # * RootDeviceName<~String> - Name of Root Device (for EBS snapshot backed AMIs) + # * BlockDevices<~Array>: + # * BlockDeviceOptions<~Hash>: + # * DeviceName<~String> - Name of the Block Device + # * VirtualName<~String> - Name of the Virtual Device + # * SnapshotId<~String> - id of the EBS Snapshot + # * VolumeSize<~Integer> - Size of the snapshot (optional) + # * NoDevice<~Boolean> - Do not use an ebs device (def: true) + # * DeleteOnTermation<~Boolean> - Delete EBS volume on instance term (def: true) + # * Options<~Hash>: + # * Architecture<~String> - i386 or x86_64 + # * KernelId<~String> - kernelId + # * RamdiskId<~String> - ramdiskId + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'imageId'<~String> - Id of newly created AMI + + # + + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-RegisterImage.html] + + def register_image(name, description, location, block_devices=[], options={}) + common_options = { + 'Action' => 'RegisterImage', + 'Name' => name, + 'Description' => description, + :parser => Fog::Parsers::Compute::AWS::RegisterImage.new + } + + # This determines if we are doing a snapshot or a S3 backed AMI. + if(location =~ /^\/dev\/(xvd|sd)[a-p]\d{0,2}$/) + common_options['RootDeviceName'] = location + else + common_options['ImageLocation'] = location + end + + block_devices.each_with_index do |bd, index| + index += 1 + ["DeviceName","VirtualName"].each do |n| + common_options["BlockDeviceMapping.#{index}.#{n}"] = bd[n] if bd[n] + end + ["SnapshotId","VolumeSize","NoDevice","DeleteOnTermination"].each do |n| + common_options["BlockDeviceMapping.#{index}.Ebs.#{n}"] = bd[n] if bd[n] + end + end + + request(common_options.merge!(options)) + end + end + + class Mock + def register_image(name, description, location, block_devices=[], options={}) + unless name.empty? + image = { + 'imageId' => Fog::AWS::Mock.image_id, + 'imageLocation' => '', + 'imageState' => 'pending', + 'imageOwnerId' => self.data[:owner_id], + 'isPublic' => false, + 'productCodes' => [], + 'architecture' => options['Architecture'] || 'i386', + 'imageType' => 'machine', + 'kernelId' => options['KernelId'] || Fog::AWS::Mock.kernel_id, + 'ramdiskId' => options['RamdiskId'] || Fog::AWS::Mock.ramdisk_id, + 'platform' => 'Linux', + 'stateReason' => {}, + 'imageOwnerAlias' => self.data[:owner_id], + 'name' => name, + 'description' => description, + 'rootDeviceType' => '', + 'rootDeviceName' => '', + 'blockDeviceMapping' => [], + 'virtualizationType' => 'paravirtual', + 'hypervisor' => 'xen', + 'registered' => Time.now + } + + if location[/^\/dev\/(xvd|sd)[a-p]\d{0,2}$/] + image['rootDeviceName'] = location + image['rootDeviceType'] = 'ebs' + else + image['imageLocation'] = location + end + + block_devices.each do |bd| + block_device_mapping = { + 'ebs' => {} + } + ["DeviceName","VirtualName"].each do |n| + block_device_mapping[n] = bd[n] if bd[n] + end + ["SnapshotId","VolumeSize","NoDevice","DeleteOnTermination"].each do |n| + block_device_mapping['ebs'][n] = bd[n] if bd[n] + end + image['blockDeviceMapping'] << block_device_mapping + end + + self.data[:images][image['imageId']] = image + + response = Excon::Response.new + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'imageId' => image['imageId'] + } + response + else + message = 'MissingParameter => ' + if name.empty? + message << 'The request must contain the parameter name' + end + raise Fog::Compute::AWS::Error.new(message) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/release_address.rb b/lib/fog/aws/requests/compute/release_address.rb new file mode 100644 index 000000000..2294d0669 --- /dev/null +++ b/lib/fog/aws/requests/compute/release_address.rb @@ -0,0 +1,59 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Release an elastic IP address. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-ReleaseAddress.html] + # + # non-VPC: requires public_ip only + # VPC: requires allocation_id only + def release_address(ip_or_allocation) + field = if ip_or_allocation.to_s =~ /^(\d|\.)+$/ + "PublicIp" + else + "AllocationId" + end + request( + 'Action' => 'ReleaseAddress', + field => ip_or_allocation, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def release_address(public_ip_or_allocation_id) + response = Excon::Response.new + + address = self.data[:addresses][public_ip_or_allocation_id] || self.data[:addresses].values.find {|a| a['allocationId'] == public_ip_or_allocation_id } + + if address + if address['allocationId'] && public_ip_or_allocation_id == address['publicIp'] + raise Fog::Compute::AWS::Error, "InvalidParameterValue => You must specify an allocation id when releasing a VPC elastic IP address" + end + + self.data[:addresses].delete(address['publicIp']) + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::Error.new("AuthFailure => The address '#{public_ip_or_allocation_id}' does not belong to you.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/replace_network_acl_association.rb b/lib/fog/aws/requests/compute/replace_network_acl_association.rb new file mode 100644 index 000000000..4a7e36c9c --- /dev/null +++ b/lib/fog/aws/requests/compute/replace_network_acl_association.rb @@ -0,0 +1,66 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/replace_network_acl_association' + + # Replace the network ACL for a subnet with a + # + # ==== Parameters + # * association_id<~String> - The ID of the current association between the original network ACL and the subnet + # * network_acl_id<~String> - The ID of the network ACL + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-ReplaceNetworkAclAssociation.html] + def replace_network_acl_association(association_id, network_acl_id) + request({ + 'Action' => 'ReplaceNetworkAclAssociation', + 'AssociationId' => association_id, + 'NetworkAclId' => network_acl_id, + :parser => Fog::Parsers::Compute::AWS::ReplaceNetworkAclAssociation.new + }) + end + end + + class Mock + def replace_network_acl_association(association_id, network_acl_id) + response = Excon::Response.new + if self.data[:network_acls][network_acl_id] + # find the old assoc + old_nacl = self.data[:network_acls].values.find do |n| + n['associationSet'].find { |assoc| assoc['networkAclAssociationId'] == association_id } + end + + unless old_nacl + raise Fog::Compute::AWS::Error.new("Invalid association_id #{association_id}") + end + + subnet_id = old_nacl['associationSet'].find { |assoc| assoc['networkAclAssociationId'] == association_id }['subnetId'] + old_nacl['associationSet'].delete_if { |assoc| assoc['networkAclAssociationId'] == association_id } + + id = Fog::AWS::Mock.network_acl_association_id + self.data[:network_acls][network_acl_id]['associationSet'] << { + 'networkAclAssociationId' => id, + 'networkAclId' => network_acl_id, + 'subnetId' => subnet_id, + } + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'newAssociationId' => id + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network ACL '#{network_acl_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/replace_network_acl_entry.rb b/lib/fog/aws/requests/compute/replace_network_acl_entry.rb new file mode 100644 index 000000000..c8624e46d --- /dev/null +++ b/lib/fog/aws/requests/compute/replace_network_acl_entry.rb @@ -0,0 +1,81 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Replaces a Network ACL entry with the same rule number + # + # ==== Parameters + # * network_acl_id<~String> - The ID of the ACL to add this entry to + # * rule_number<~Integer> - The rule number for the entry, between 100 and 32766 + # * protocol<~Integer> - The IP protocol to which the rule applies. You can use -1 to mean all protocols. + # * rule_action<~String> - Allows or denies traffic that matches the rule. (either allow or deny) + # * cidr_block<~String> - The CIDR range to allow or deny + # * egress<~Boolean> - Indicates whether this rule applies to egress traffic from the subnet (true) or ingress traffic to the subnet (false). + # * options<~Hash>: + # * 'Icmp.Code' - ICMP code, required if protocol is 1 + # * 'Icmp.Type' - ICMP type, required if protocol is 1 + # * 'PortRange.From' - The first port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # * 'PortRange.To' - The last port in the range, required if protocol is 6 (TCP) or 17 (UDP) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - Returns true if the request succeeds. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-ReplaceNetworkAclEntry.html] + def replace_network_acl_entry(network_acl_id, rule_number, protocol, rule_action, cidr_block, egress, options = {}) + request({ + 'Action' => 'ReplaceNetworkAclEntry', + 'NetworkAclId' => network_acl_id, + 'RuleNumber' => rule_number, + 'Protocol' => protocol, + 'RuleAction' => rule_action, + 'Egress' => egress, + 'CidrBlock' => cidr_block, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(options)) + end + end + + class Mock + def replace_network_acl_entry(network_acl_id, rule_number, protocol, rule_action, cidr_block, egress, options = {}) + response = Excon::Response.new + if self.data[:network_acls][network_acl_id] + + unless self.data[:network_acls][network_acl_id]['entrySet'].find { |r| r['ruleNumber'] == rule_number && r['egress'] == egress } + raise Fog::Compute::AWS::Error.new("No rule with that number") + end + self.data[:network_acls][network_acl_id]['entrySet'].delete_if { |r| r['ruleNumber'] == rule_number && r['egress'] == egress } + + data = { + 'ruleNumber' => rule_number, + 'protocol' => protocol, + 'ruleAction' => rule_action, + 'egress' => egress, + 'cidrBlock' => cidr_block, + 'icmpTypeCode' => {}, + 'portRange' => {} + } + data['icmpTypeCode']['code'] = options['Icmp.Code'] if options['Icmp.Code'] + data['icmpTypeCode']['type'] = options['Icmp.Type'] if options['Icmp.Type'] + data['portRange']['from'] = options['PortRange.From'] if options['PortRange.From'] + data['portRange']['to'] = options['PortRange.To'] if options['PortRange.To'] + self.data[:network_acls][network_acl_id]['entrySet'] << data + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The network ACL '#{network_acl_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/replace_route.rb b/lib/fog/aws/requests/compute/replace_route.rb new file mode 100755 index 000000000..e34f73247 --- /dev/null +++ b/lib/fog/aws/requests/compute/replace_route.rb @@ -0,0 +1,80 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Replaces a route in a route table within a VPC. + # + # ==== Parameters + # * RouteTableId<~String> - The ID of the route table for the route. + # * options<~Hash>: + # * DestinationCidrBlock<~String> - The CIDR address block used for the destination match. Routing decisions are based on the most specific match. + # * GatewayId<~String> - The ID of an Internet gateway attached to your VPC. + # * InstanceId<~String> - The ID of a NAT instance in your VPC. The operation fails if you specify an instance ID unless exactly one network interface is attached. + # * NetworkInterfaceId<~String> - The ID of a network interface. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of the request + # * 'return'<~Boolean> - Returns true if the request succeeds. Otherwise, returns an error. + # + # {Amazon API Reference}[http://docs.aws.amazon.com/AwsEC2/latest/APIReference/ApiReference-query-ReplaceRoute.html] + def replace_route(route_table_id, destination_cidr_block, options = {}) + options['DestinationCidrBlock'] ||= destination_cidr_block + + request({ + 'Action' => 'ReplaceRoute', + 'RouteTableId' => route_table_id, + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(options)) + end + end + + class Mock + def replace_route(route_table_id, destination_cidr_block, options = {}) + options['instanceOwnerId'] ||= nil + options['DestinationCidrBlock'] ||= destination_cidr_block + + route_table = self.data[:route_tables].find { |routetable| routetable["routeTableId"].eql? route_table_id } + if !route_table.nil? && destination_cidr_block + if !options['gatewayId'].nil? || !options['instanceId'].nil? || !options['networkInterfaceId'].nil? + if !options['gatewayId'].nil? && self.internet_gateways.all('internet-gateway-id'=>options['gatewayId']).first.nil? + raise Fog::Compute::AWS::NotFound.new("The gateway ID '#{options['gatewayId']}' does not exist") + elsif !options['instanceId'].nil? && self.servers.all('instance-id'=>options['instanceId']).first.nil? + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{options['instanceId']}' does not exist") + elsif !options['networkInterfaceId'].nil? && self.network_interfaces.all('networkInterfaceId'=>options['networkInterfaceId']).first.nil? + raise Fog::Compute::AWS::NotFound.new("The networkInterface ID '#{options['networkInterfaceId']}' does not exist") + elsif route_table['routeSet'].find { |route| route['destinationCidrBlock'].eql? destination_cidr_block }.nil? + raise Fog::Compute::AWS::Error, "RouteAlreadyExists => The route identified by #{destination_cidr_block} doesn't exist." + else + response = Excon::Response.new + route_set = route_table['routeSet'].find { |routeset| routeset['destinationCidrBlock'].eql? destination_cidr_block } + route_set.merge!(options) + route_set['state'] = 'pending' + route_set['origin'] = 'ReplaceRoute' + + response.status = 200 + response.body = { + 'requestId'=> Fog::AWS::Mock.request_id, + 'return' => true + } + response + end + else + message = 'MissingParameter => ' + message << 'The request must contain either a gateway id, a network interface id, or an instance id' + raise Fog::Compute::AWS::Error.new(message) + end + elsif route_table.nil? + raise Fog::Compute::AWS::NotFound.new("The routeTable ID '#{route_table_id}' does not exist") + elsif destination_cidr_block.empty? + raise Fog::Compute::AWS::InvalidParameterValue.new("Value () for parameter destinationCidrBlock is invalid. This is not a valid CIDR block.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/request_spot_instances.rb b/lib/fog/aws/requests/compute/request_spot_instances.rb new file mode 100644 index 000000000..e4e8c2002 --- /dev/null +++ b/lib/fog/aws/requests/compute/request_spot_instances.rb @@ -0,0 +1,96 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/spot_instance_requests' + + # Launch specified instances + # + # ==== Parameters + # * 'image_id'<~String> - Id of machine image to load on instances + # * 'instance_type'<~String> - Type of instance + # * 'spot_price'<~Float> - maximum hourly price for instances launched + # * options<~Hash>: + # * 'AvailabilityZoneGroup'<~String> - specify whether or not to launch all instances in the same availability group + # * 'InstanceCount'<~Integer> - maximum number of instances to launch + # * 'LaunchGroup'<~String> - whether or not to launch/shutdown instances as a group + # * 'LaunchSpecification.BlockDeviceMapping'<~Array>: array of hashes + # * 'DeviceName'<~String> - where the volume will be exposed to instance + # * 'VirtualName'<~String> - volume virtual device name + # * 'Ebs.SnapshotId'<~String> - id of snapshot to boot volume from + # * 'Ebs.NoDevice'<~String> - specifies that no device should be mapped + # * 'Ebs.VolumeSize'<~String> - size of volume in GiBs required unless snapshot is specified + # * 'Ebs.DeleteOnTermination'<~String> - specifies whether or not to delete the volume on instance termination + # * 'LaunchSpecification.KeyName'<~String> - Name of a keypair to add to booting instances + # * 'LaunchSpecification.Monitoring.Enabled'<~Boolean> - Enables monitoring, defaults to disabled + # * 'LaunchSpecification.SubnetId'<~String> - VPC subnet ID in which to launch the instance + # * 'LaunchSpecification.Placement.AvailabilityZone'<~String> - Placement constraint for instances + # * 'LaunchSpecification.SecurityGroup'<~Array> or <~String> - Name of security group(s) for instances, not supported in VPC + # * 'LaunchSpecification.SecurityGroupId'<~Array> or <~String> - Id of security group(s) for instances, use this or LaunchSpecification.SecurityGroup + # * 'LaunchSpecification.UserData'<~String> - Additional data to provide to booting instances + # * 'LaunchSpecification.EbsOptimized'<~Boolean> - Whether the instance is optimized for EBS I/O + # * 'Type'<~String> - spot instance request type in ['one-time', 'persistent'] + # * 'ValidFrom'<~Time> - start date for request + # * 'ValidUntil'<~Time> - end date for request + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'spotInstanceRequestSet'<~Array>: + # * 'createTime'<~Time> - time of instance request creation + # * 'instanceId'<~String> - instance id if one has been launched to fulfill request + # * 'launchedAvailabilityZone'<~String> - availability zone of instance if one has been launched to fulfill request + # * 'launchSpecification'<~Hash>: + # * 'blockDeviceMapping'<~Hash> - list of block device mappings for instance + # * 'groupSet'<~String> - security group(s) for instance + # * 'keyName'<~String> - keypair name for instance + # * 'imageId'<~String> - AMI for instance + # * 'instanceType'<~String> - type for instance + # * 'monitoring'<~Boolean> - monitoring status for instance + # * 'subnetId'<~String> - VPC subnet ID for instance + # * 'productDescription'<~String> - general description of AMI + # * 'spotInstanceRequestId'<~String> - id of spot instance request + # * 'spotPrice'<~Float> - maximum price for instances to be launched + # * 'state'<~String> - spot instance request state + # * 'type'<~String> - spot instance request type + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-RequestSpotInstances.html] + def request_spot_instances(image_id, instance_type, spot_price, options = {}) + if block_device_mapping = options.delete('LaunchSpecification.BlockDeviceMapping') + block_device_mapping.each_with_index do |mapping, index| + for key, value in mapping + options.merge!({ format("LaunchSpecification.BlockDeviceMapping.%d.#{key}", index) => value }) + end + end + end + if security_groups = options.delete('LaunchSpecification.SecurityGroup') + options.merge!(Fog::AWS.indexed_param('LaunchSpecification.SecurityGroup', [*security_groups])) + end + if security_group_ids = options.delete('LaunchSpecification.SecurityGroupId') + options.merge!(Fog::AWS.indexed_param('LaunchSpecification.SecurityGroupId', [*security_group_ids])) + end + if options['LaunchSpecification.UserData'] + options['LaunchSpecification.UserData'] = Base64.encode64(options['LaunchSpecification.UserData']) + end + + if options['ValidFrom'] && options['ValidFrom'].is_a?(Time) + options['ValidFrom'] = options['ValidFrom'].iso8601 + end + + if options['ValidUntil'] && options['ValidUntil'].is_a?(Time) + options['ValidUntil'] = options['ValidUntil'].iso8601 + end + + request({ + 'Action' => 'RequestSpotInstances', + 'LaunchSpecification.ImageId' => image_id, + 'LaunchSpecification.InstanceType' => instance_type, + 'SpotPrice' => spot_price, + :parser => Fog::Parsers::Compute::AWS::SpotInstanceRequests.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/reset_network_interface_attribute.rb b/lib/fog/aws/requests/compute/reset_network_interface_attribute.rb new file mode 100644 index 000000000..0ab5751b0 --- /dev/null +++ b/lib/fog/aws/requests/compute/reset_network_interface_attribute.rb @@ -0,0 +1,56 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Resets a network interface attribute value + # + # ==== Parameters + # * network_interface_id<~String> - The ID of the network interface you want to describe an attribute of + # * attribute<~String> - The attribute to reset, only 'sourceDestCheck' is supported. + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/2012-03-01/APIReference/ApiReference-query-DescribeNetworkInterfaceAttribute.html] + def reset_network_interface_attribute(network_interface_id, attribute) + if attribute != 'sourceDestCheck' + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + request( + 'Action' => 'ResetNetworkInterfaceAttribute', + 'NetworkInterfaceId' => network_interface_id, + 'Attribute' => attribute, + :parser => Fog::Parsers::Compute::AWS::Basic.new + ) + end + end + + class Mock + def reset_network_interface_attribute(network_interface_id, attribute) + response = Excon::Response.new + if self.data[:network_interfaces][network_interface_id] + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + if attribute == 'sourceDestCheck' + self.data[:network_interfaces][network_interface_id]['sourceDestCheck'] = true + else + raise Fog::Compute::AWS::Error.new("Illegal attribute '#{attribute}' specified") + end + response + else + raise Fog::Compute::AWS::NotFound.new("The network interface '#{network_interface_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/revoke_security_group_ingress.rb b/lib/fog/aws/requests/compute/revoke_security_group_ingress.rb new file mode 100644 index 000000000..53e813152 --- /dev/null +++ b/lib/fog/aws/requests/compute/revoke_security_group_ingress.rb @@ -0,0 +1,98 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/basic' + + # Remove permissions from a security group + # + # ==== Parameters + # * group_name<~String> - Name of group, optional (can also be specifed as GroupName in options) + # * options<~Hash>: + # * 'GroupName'<~String> - Name of security group to modify + # * 'GroupId'<~String> - Id of security group to modify + # * 'SourceSecurityGroupName'<~String> - Name of security group to authorize + # * 'SourceSecurityGroupOwnerId'<~String> - Name of owner to authorize + # or + # * 'CidrIp'<~String> - CIDR range + # * 'FromPort'<~Integer> - Start of port range (or -1 for ICMP wildcard) + # * 'IpProtocol'<~String> - Ip protocol, must be in ['tcp', 'udp', 'icmp'] + # * 'ToPort'<~Integer> - End of port range (or -1 for ICMP wildcard) + # or + # * 'IpPermissions'<~Array>: + # * permission<~Hash>: + # * 'FromPort'<~Integer> - Start of port range (or -1 for ICMP wildcard) + # * 'Groups'<~Array>: + # * group<~Hash>: + # * 'GroupName'<~String> - Name of security group to authorize + # * 'UserId'<~String> - Name of owner to authorize + # * 'IpProtocol'<~String> - Ip protocol, must be in ['tcp', 'udp', 'icmp'] + # * 'IpRanges'<~Array>: + # * ip_range<~Hash>: + # * 'CidrIp'<~String> - CIDR range + # * 'ToPort'<~Integer> - End of port range (or -1 for ICMP wildcard) + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'return'<~Boolean> - success? + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-RevokeSecurityGroupIngress.html] + def revoke_security_group_ingress(group_name, options = {}) + options = Fog::AWS.parse_security_group_options(group_name, options) + + if ip_permissions = options.delete('IpPermissions') + options.merge!(indexed_ip_permissions_params(ip_permissions)) + end + + request({ + 'Action' => 'RevokeSecurityGroupIngress', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::Basic.new + }.merge!(options)) + end + end + + class Mock + def revoke_security_group_ingress(group_name, options = {}) + options = Fog::AWS.parse_security_group_options(group_name, options) + if options.key?('GroupName') + group_name = options['GroupName'] + else + group_name = self.data[:security_groups].reject { |k,v| v['groupId'] != options['GroupId'] } .keys.first + end + + response = Excon::Response.new + group = self.data[:security_groups][group_name] + + if group + verify_permission_options(options, group['vpcId'] != nil) + + normalized_permissions = normalize_permissions(options) + + normalized_permissions.each do |permission| + if matching_permission = find_matching_permission(group, permission) + matching_permission['ipRanges'] -= permission['ipRanges'] + matching_permission['groups'] -= permission['groups'] + + if matching_permission['ipRanges'].empty? && matching_permission['groups'].empty? + group['ipPermissions'].delete(matching_permission) + end + end + end + + response.status = 200 + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'return' => true + } + response + else + raise Fog::Compute::AWS::NotFound.new("The security group '#{group_name}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/run_instances.rb b/lib/fog/aws/requests/compute/run_instances.rb new file mode 100644 index 000000000..e442e8c73 --- /dev/null +++ b/lib/fog/aws/requests/compute/run_instances.rb @@ -0,0 +1,274 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/run_instances' + + # Launch specified instances + # + # ==== Parameters + # * image_id<~String> - Id of machine image to load on instances + # * min_count<~Integer> - Minimum number of instances to launch. If this + # exceeds the count of available instances, no instances will be + # launched. Must be between 1 and maximum allowed for your account + # (by default the maximum for an account is 20) + # * max_count<~Integer> - Maximum number of instances to launch. If this + # exceeds the number of available instances, the largest possible + # number of instances above min_count will be launched instead. Must + # be between 1 and maximum allowed for you account + # (by default the maximum for an account is 20) + # * options<~Hash>: + # * 'Placement.AvailabilityZone'<~String> - Placement constraint for instances + # * 'Placement.GroupName'<~String> - Name of existing placement group to launch instance into + # * 'Placement.Tenancy'<~String> - Tenancy option in ['dedicated', 'default'], defaults to 'default' + # * 'BlockDeviceMapping'<~Array>: array of hashes + # * 'DeviceName'<~String> - where the volume will be exposed to instance + # * 'VirtualName'<~String> - volume virtual device name + # * 'Ebs.SnapshotId'<~String> - id of snapshot to boot volume from + # * 'Ebs.VolumeSize'<~String> - size of volume in GiBs required unless snapshot is specified + # * 'Ebs.DeleteOnTermination'<~Boolean> - specifies whether or not to delete the volume on instance termination + # * 'Ebs.Encrypted'<~Boolean> - specifies whether or not the volume is to be encrypted unless snapshot is specified + # * 'Ebs.VolumeType'<~String> - Type of EBS volue. Valid options in ['standard', 'io1'] default is 'standard'. + # * 'Ebs.Iops'<~String> - The number of I/O operations per second (IOPS) that the volume supports. Required when VolumeType is 'io1' + # * 'NetworkInterfaces'<~Array>: array of hashes + # * 'NetworkInterfaceId'<~String> - An existing interface to attach to a single instance + # * 'DeviceIndex'<~String> - The device index. Applies both to attaching an existing network interface and creating a network interface + # * 'SubnetId'<~String> - The subnet ID. Applies only when creating a network interface + # * 'Description'<~String> - A description. Applies only when creating a network interface + # * 'PrivateIpAddress'<~String> - The primary private IP address. Applies only when creating a network interface + # * 'SecurityGroupId'<~Array> or <~String> - ids of security group(s) for network interface. Applies only when creating a network interface. + # * 'DeleteOnTermination'<~String> - Indicates whether to delete the network interface on instance termination. + # * 'PrivateIpAddresses.PrivateIpAddress'<~String> - The private IP address. This parameter can be used multiple times to specify explicit private IP addresses for a network interface, but only one private IP address can be designated as primary. + # * 'PrivateIpAddresses.Primary'<~Bool> - Indicates whether the private IP address is the primary private IP address. + # * 'SecondaryPrivateIpAddressCount'<~Bool> - The number of private IP addresses to assign to the network interface. + # * 'AssociatePublicIpAddress'<~String> - Indicates whether to assign a public IP address to an instance in a VPC. The public IP address is assigned to a specific network interface + # * 'ClientToken'<~String> - unique case-sensitive token for ensuring idempotency + # * 'DisableApiTermination'<~Boolean> - specifies whether or not to allow termination of the instance from the api + # * 'SecurityGroup'<~Array> or <~String> - Name of security group(s) for instances (not supported for VPC) + # * 'SecurityGroupId'<~Array> or <~String> - id's of security group(s) for instances, use this or SecurityGroup + # * 'InstanceInitiatedShutdownBehaviour'<~String> - specifies whether volumes are stopped or terminated when instance is shutdown, in [stop, terminate] + # * 'InstanceType'<~String> - Type of instance to boot. Valid options + # in ['t1.micro', 't2.micro', 't2.small', 't2.medium', 'm1.small', 'm1.medium', 'm1.large', 'm1.xlarge', 'c1.medium', 'c1.xlarge', 'c3.large', 'c3.xlarge', 'c3.2xlarge', 'c3.4xlarge', 'c3.8xlarge', 'g2.2xlarge', 'hs1.8xlarge', 'm2.xlarge', 'm2.2xlarge', 'm2.4xlarge', 'cr1.8xlarge', 'm3.xlarge', 'm3.2xlarge', 'hi1.4xlarge', 'cc1.4xlarge', 'cc2.8xlarge', 'cg1.4xlarge', 'i2.xlarge', 'i2.2xlarge', 'i2.4xlarge', 'i2.8xlarge'] + # default is 'm1.small' + # * 'KernelId'<~String> - Id of kernel with which to launch + # * 'KeyName'<~String> - Name of a keypair to add to booting instances + # * 'Monitoring.Enabled'<~Boolean> - Enables monitoring, defaults to + # disabled + # * 'PrivateIpAddress<~String> - VPC option to specify ip address within subnet + # * 'RamdiskId'<~String> - Id of ramdisk with which to launch + # * 'SubnetId'<~String> - VPC option to specify subnet to launch instance into + # * 'UserData'<~String> - Additional data to provide to booting instances + # * 'EbsOptimized'<~Boolean> - Whether the instance is optimized for EBS I/O + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'groupSet'<~Array>: groups the instances are members in + # * 'groupName'<~String> - Name of group + # * 'instancesSet'<~Array>: returned instances + # * instance<~Hash>: + # * 'amiLaunchIndex'<~Integer> - reference to instance in launch group + # * 'architecture'<~String> - architecture of image in [i386, x86_64] + # * 'blockDeviceMapping'<~Array> + # * 'attachTime'<~Time> - time of volume attachment + # * 'deleteOnTermination'<~Boolean> - whether or not to delete volume on termination + # * 'deviceName'<~String> - specifies how volume is exposed to instance + # * 'status'<~String> - status of attached volume + # * 'volumeId'<~String> - Id of attached volume + # * 'dnsName'<~String> - public dns name, blank until instance is running + # * 'imageId'<~String> - image id of ami used to launch instance + # * 'instanceId'<~String> - id of the instance + # * 'instanceState'<~Hash>: + # * 'code'<~Integer> - current status code + # * 'name'<~String> - current status name + # * 'instanceType'<~String> - type of instance + # * 'ipAddress'<~String> - public ip address assigned to instance + # * 'kernelId'<~String> - Id of kernel used to launch instance + # * 'keyName'<~String> - name of key used launch instances or blank + # * 'launchTime'<~Time> - time instance was launched + # * 'monitoring'<~Hash>: + # * 'state'<~Boolean - state of monitoring + # * 'placement'<~Hash>: + # * 'availabilityZone'<~String> - Availability zone of the instance + # * 'privateDnsName'<~String> - private dns name, blank until instance is running + # * 'privateIpAddress'<~String> - private ip address assigned to instance + # * 'productCodes'<~Array> - Product codes for the instance + # * 'ramdiskId'<~String> - Id of ramdisk used to launch instance + # * 'reason'<~String> - reason for most recent state transition, or blank + # * 'rootDeviceName'<~String> - specifies how the root device is exposed to the instance + # * 'rootDeviceType'<~String> - root device type used by AMI in [ebs, instance-store] + # * 'ebsOptimized'<~Boolean> - Whether the instance is optimized for EBS I/O + # * 'ownerId'<~String> - Id of owner + # * 'requestId'<~String> - Id of request + # * 'reservationId'<~String> - Id of reservation + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-RunInstances.html] + def run_instances(image_id, min_count, max_count, options = {}) + if block_device_mapping = options.delete('BlockDeviceMapping') + block_device_mapping.each_with_index do |mapping, index| + for key, value in mapping + options.merge!({ format("BlockDeviceMapping.%d.#{key}", index) => value }) + end + end + end + if security_groups = options.delete('SecurityGroup') + options.merge!(Fog::AWS.indexed_param('SecurityGroup', [*security_groups])) + end + if security_group_ids = options.delete('SecurityGroupId') + options.merge!(Fog::AWS.indexed_param('SecurityGroupId', [*security_group_ids])) + end + if options['UserData'] + options['UserData'] = Base64.encode64(options['UserData']) + end + if network_interfaces = options.delete('NetworkInterfaces') + network_interfaces.each_with_index do |mapping, index| + iface = format("NetworkInterface.%d", index) + for key, value in mapping + case key + when "SecurityGroupId" + options.merge!(Fog::AWS.indexed_param("#{iface}.SecurityGroupId", [*value])) + else + options.merge!({ "#{iface}.#{key}" => value }) + end + end + end + end + + idempotent = !(options['ClientToken'].nil? || options['ClientToken'].empty?) + + request({ + 'Action' => 'RunInstances', + 'ImageId' => image_id, + 'MinCount' => min_count, + 'MaxCount' => max_count, + :idempotent => idempotent, + :parser => Fog::Parsers::Compute::AWS::RunInstances.new + }.merge!(options)) + end + end + + class Mock + def run_instances(image_id, min_count, max_count, options = {}) + response = Excon::Response.new + response.status = 200 + + group_set = [ (options['SecurityGroup'] || 'default') ].flatten + instances_set = [] + reservation_id = Fog::AWS::Mock.reservation_id + + if options['KeyName'] && describe_key_pairs('key-name' => options['KeyName']).body['keySet'].empty? + raise Fog::Compute::AWS::NotFound.new("The key pair '#{options['KeyName']}' does not exist") + end + + min_count.times do |i| + instance_id = Fog::AWS::Mock.instance_id + availability_zone = options['Placement.AvailabilityZone'] || Fog::AWS::Mock.availability_zone(@region) + + block_device_mapping = (options['BlockDeviceMapping'] || []).reduce([]) do |mapping, device| + device_name = device.fetch("DeviceName", "/dev/sda1") + volume_size = device.fetch("Ebs.VolumeSize", 15) # @todo should pull this from the image + delete_on_termination = device.fetch("Ebs.DeleteOnTermination", true) # @todo should pull this from the image + + volume_id = create_volume(availability_zone, volume_size).data[:body]["volumeId"] + + self.data[:volumes][volume_id].merge!("DeleteOnTermination" => delete_on_termination) + + mapping << { + "deviceName" => device_name, + "volumeId" => volume_id, + "status" => "attached", + "attachTime" => Time.now, + "deleteOnTermination" => delete_on_termination, + } + end + + if options['SubnetId'] + if options['PrivateIpAddress'] + ni_options = {'PrivateIpAddress' => options['PrivateIpAddress']} + else + ni_options = {} + end + + network_interface_id = create_network_interface(options['SubnetId'], ni_options).body['networkInterface']['networkInterfaceId'] + end + + network_interfaces = (options['NetworkInterfaces'] || []).reduce([]) do |mapping, device| + device_index = device.fetch("DeviceIndex", 0) + subnet_id = device.fetch("SubnetId", options[:subnet_id] || Fog::AWS::Mock.subnet_id) + private_ip_address = device.fetch("PrivateIpAddress", options[:private_ip_address] || Fog::AWS::Mock.private_ip_address) + delete_on_termination = device.fetch("DeleteOnTermination", true) + description = device.fetch("Description", "mock_network_interface") + security_group_id = device.fetch("SecurityGroupId", self.data[:security_groups]['default']['groupId']) + interface_options = { + "PrivateIpAddress" => private_ip_address, + "GroupSet" => device.fetch("GroupSet", [security_group_id]), + "Description" => description + } + + interface_id = device.fetch("NetworkInterfaceId", create_network_interface(subnet_id, interface_options)) + + mapping << { + "networkInterfaceId" => interface_id, + "subnetId" => subnet_id, + "status" => "attached", + "attachTime" => Time.now, + "deleteOnTermination" => delete_on_termination, + } + end + + instance = { + 'amiLaunchIndex' => i, + 'associatePublicIP' => options['associatePublicIP'] || false, + 'architecture' => 'i386', + 'blockDeviceMapping' => block_device_mapping, + 'networkInterfaces' => network_interfaces, + 'clientToken' => options['clientToken'], + 'dnsName' => nil, + 'ebsOptimized' => options['EbsOptimized'] || false, + 'hypervisor' => 'xen', + 'imageId' => image_id, + 'instanceId' => instance_id, + 'instanceState' => { 'code' => 0, 'name' => 'pending' }, + 'instanceType' => options['InstanceType'] || 'm1.small', + 'kernelId' => options['KernelId'] || Fog::AWS::Mock.kernel_id, + 'keyName' => options['KeyName'], + 'launchTime' => Time.now, + 'monitoring' => { 'state' => options['Monitoring.Enabled'] || false }, + 'placement' => { 'availabilityZone' => availability_zone, 'groupName' => nil, 'tenancy' => options['Placement.Tenancy'] || 'default' }, + 'privateDnsName' => nil, + 'productCodes' => [], + 'reason' => nil, + 'rootDeviceName' => block_device_mapping.first && block_device_mapping.first["deviceName"], + 'rootDeviceType' => 'instance-store', + 'virtualizationType' => 'paravirtual' + } + instances_set << instance + self.data[:instances][instance_id] = instance.merge({ + 'groupIds' => [], + 'groupSet' => group_set, + 'iamInstanceProfile' => {}, + 'ownerId' => self.data[:owner_id], + 'reservationId' => reservation_id, + 'stateReason' => {} + }) + + if options['SubnetId'] + self.data[:instances][instance_id]['vpcId'] = self.data[:subnets].find{|subnet| subnet['subnetId'] == options['SubnetId'] }['vpcId'] + + attachment_id = attach_network_interface(network_interface_id, instance_id, '0').data[:body]['attachmentId'] + modify_network_interface_attribute(network_interface_id, 'attachment', {'attachmentId' => attachment_id, 'deleteOnTermination' => 'true'}) + end + end + response.body = { + 'groupSet' => group_set, + 'instancesSet' => instances_set, + 'ownerId' => self.data[:owner_id], + 'requestId' => Fog::AWS::Mock.request_id, + 'reservationId' => reservation_id + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/start_instances.rb b/lib/fog/aws/requests/compute/start_instances.rb new file mode 100644 index 000000000..a48d2f4e5 --- /dev/null +++ b/lib/fog/aws/requests/compute/start_instances.rb @@ -0,0 +1,58 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/start_stop_instances' + + # Start specified instance + # + # ==== Parameters + # * instance_id<~Array> - Id of instance to start + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * TODO: fill in the blanks + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-StartInstances.html] + def start_instances(instance_id) + params = Fog::AWS.indexed_param('InstanceId', instance_id) + request({ + 'Action' => 'StartInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::StartStopInstances.new + }.merge!(params)) + end + end + + class Mock + def start_instances(instance_id) + instance_ids = Array(instance_id) + + instance_set = self.data[:instances].values + instance_set = apply_tag_filters(instance_set, {'instance_id' => instance_ids}, 'instanceId') + instance_set = instance_set.select {|x| instance_ids.include?(x["instanceId"]) } + + if instance_set.empty? + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_ids.first}' does not exist") + else + response = Excon::Response.new + response.status = 200 + + response.body = { + 'instancesSet' => instance_set.reduce([]) do |ia, instance| + ia << {'currentState' => { 'code' => 0, 'name' => 'pending' }, + 'previousState' => instance['instanceState'], + 'instanceId' => instance['instanceId'] } + instance['instanceState'] = {'code'=>0, 'name'=>'pending'} + ia + end + } + response + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/stop_instances.rb b/lib/fog/aws/requests/compute/stop_instances.rb new file mode 100644 index 000000000..7c4d845cb --- /dev/null +++ b/lib/fog/aws/requests/compute/stop_instances.rb @@ -0,0 +1,59 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/start_stop_instances' + + # Stop specified instance + # + # ==== Parameters + # * instance_id<~Array> - Id of instance to start + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * TODO: fill in the blanks + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-StopInstances.html] + def stop_instances(instance_id, force = false) + params = Fog::AWS.indexed_param('InstanceId', instance_id) + params.merge!('Force' => 'true') if force + request({ + 'Action' => 'StopInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::StartStopInstances.new + }.merge!(params)) + end + end + + class Mock + def stop_instances(instance_id, force = false) + instance_ids = Array(instance_id) + + instance_set = self.data[:instances].values + instance_set = apply_tag_filters(instance_set, {'instance_id' => instance_ids}, 'instanceId') + instance_set = instance_set.select {|x| instance_ids.include?(x["instanceId"]) } + + if instance_set.empty? + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_ids.first}' does not exist") + else + response = Excon::Response.new + response.status = 200 + + response.body = { + 'instancesSet' => instance_set.reduce([]) do |ia, instance| + ia << {'currentState' => { 'code' => 0, 'name' => 'stopping' }, + 'previousState' => instance['instanceState'], + 'instanceId' => instance['instanceId'] } + instance['instanceState'] = {'code'=>0, 'name'=>'stopping'} + ia + end + } + response + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/terminate_instances.rb b/lib/fog/aws/requests/compute/terminate_instances.rb new file mode 100644 index 000000000..3e4947118 --- /dev/null +++ b/lib/fog/aws/requests/compute/terminate_instances.rb @@ -0,0 +1,92 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/terminate_instances' + + # Terminate specified instances + # + # ==== Parameters + # * instance_id<~Array> - Ids of instances to terminates + # + # ==== Returns + # # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'instancesSet'<~Array>: + # * 'instanceId'<~String> - id of the terminated instance + # * 'previousState'<~Hash>: previous state of instance + # * 'code'<~Integer> - previous status code + # * 'name'<~String> - name of previous state + # * 'shutdownState'<~Hash>: shutdown state of instance + # * 'code'<~Integer> - current status code + # * 'name'<~String> - name of current state + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-TerminateInstances.html] + def terminate_instances(instance_id) + params = Fog::AWS.indexed_param('InstanceId', instance_id) + request({ + 'Action' => 'TerminateInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::TerminateInstances.new + }.merge!(params)) + end + end + + class Mock + def terminate_instances(instance_id) + response = Excon::Response.new + instance_id = [*instance_id] + if (self.data[:instances].keys & instance_id).length == instance_id.length + response.body = { + 'requestId' => Fog::AWS::Mock.request_id, + 'instancesSet' => [] + } + response.status = 200 + for id in instance_id + instance = self.data[:instances][id] + self.data[:deleted_at][id] = Time.now + code = case instance['instanceState']['name'] + when 'pending' + 0 + when 'running' + 16 + when 'shutting-down' + 32 + when 'terminated' + 48 + when 'stopping' + 64 + when 'stopped' + 80 + end + state = { 'name' => 'shutting-down', 'code' => 32} + response.body['instancesSet'] << { + 'instanceId' => id, + 'previousState' => instance['instanceState'], + 'currentState' => state + } + instance['instanceState'] = state + end + + describe_addresses.body['addressesSet'].each do |address| + if instance_id.include?(address['instanceId']) + disassociate_address(address['publicIp']) + end + end + + describe_volumes.body['volumeSet'].each do |volume| + if volume['attachmentSet'].first && instance_id.include?(volume['attachmentSet'].first['instanceId']) + detach_volume(volume['volumeId']) + end + end + + response + else + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_id}' does not exist") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/compute/unmonitor_instances.rb b/lib/fog/aws/requests/compute/unmonitor_instances.rb new file mode 100644 index 000000000..e52d552d0 --- /dev/null +++ b/lib/fog/aws/requests/compute/unmonitor_instances.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class Aws + class Real + require 'fog/aws/parsers/compute/monitor_unmonitor_instances' + + # UnMonitor specified instance + # http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-UnmonitorInstances.html + # + # ==== Parameters + # * instance_ids<~Array> - Arrays of instances Ids to monitor + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'requestId'<~String> - Id of request + # * 'instancesSet': http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-ItemType-MonitorInstancesResponseSetItemType.html + # + # {Amazon API Reference}[http://docs.amazonwebservices.com/AwsEC2/latest/APIReference/ApiReference-query-UnmonitorInstances.html] + def unmonitor_instances(instance_ids) + params = Fog::AWS.indexed_param('InstanceId', instance_ids) + request({ + 'Action' => 'UnmonitorInstances', + :idempotent => true, + :parser => Fog::Parsers::Compute::AWS::MonitorUnmonitorInstances.new + }.merge!(params)) + end + end + + class Mock + def unmonitor_instances(instance_ids) + response = Excon::Response.new + response.status = 200 + [*instance_ids].each do |instance_id| + if instance = self.data[:instances][instance_id] + instance['monitoring']['state'] = 'enabled' + else + raise Fog::Compute::AWS::NotFound.new("The instance ID '#{instance_ids}' does not exist") + end + end + instances_set = [*instance_ids].reduce([]) { |memo, id| memo << {'instanceId' => id, 'monitoring' => 'disabled'} } + response.body = {'requestId' => 'some_request_id', 'instancesSet' => instances_set} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/activate_pipeline.rb b/lib/fog/aws/requests/data_pipeline/activate_pipeline.rb new file mode 100644 index 000000000..c83a1ba2e --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/activate_pipeline.rb @@ -0,0 +1,31 @@ +module Fog + module AWS + class DataPipeline + class Real + # Activate a pipeline + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_ActivatePipeline.html + # ==== Parameters + # * PipelineId <~String> - The ID of the pipeline to activate + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def activate_pipeline(id) + params = { 'pipelineId' => id } + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.ActivatePipeline' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def activate_pipeline(id) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/create_pipeline.rb b/lib/fog/aws/requests/data_pipeline/create_pipeline.rb new file mode 100644 index 000000000..776dde281 --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/create_pipeline.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class DataPipeline + class Real + # Create a pipeline + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_CreatePipeline.html + # ==== Parameters + # * UniqueId <~String> - A unique ID for of the pipeline + # * Name <~String> - The name of the pipeline + # * Tags <~Hash> - Key/value string pairs to categorize the pipeline + # * Description <~String> - Description of the pipeline + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_pipeline(unique_id, name, description=nil, tags=nil) + params = { + 'uniqueId' => unique_id, + 'name' => name, + } + params['tags'] = tags.map {|k,v| {"key" => k.to_s, "value" => v.to_s}} unless tags.nil? || tags.empty? + params['Description'] = description if description + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.CreatePipeline' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def create_pipeline(unique_id, name, description=nil, tags=nil) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/delete_pipeline.rb b/lib/fog/aws/requests/data_pipeline/delete_pipeline.rb new file mode 100644 index 000000000..e1bcb1f6f --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/delete_pipeline.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class DataPipeline + class Real + # Delete a pipeline + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_DeletePipeline.html + # ==== Parameters + # * PipelineId <~String> - The id of the pipeline to delete + # ==== Returns + # * success<~Boolean> - Whether the delete was successful + def delete_pipeline(id) + params = { 'pipelineId' => id } + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.DeletePipeline' }, + }) + + 200 == response.status + end + end + + class Mock + def delete_pipeline(id) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/describe_objects.rb b/lib/fog/aws/requests/data_pipeline/describe_objects.rb new file mode 100644 index 000000000..bac8b78d9 --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/describe_objects.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class DataPipeline + class Real + # Queries a pipeline for the names of objects that match a specified set of conditions. + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_DescribeObjects.html + # ==== Parameters + # * PipelineId <~String> - The ID of the pipeline + # * ObjectIds <~Array> - Identifiers of the pipeline objects that contain the definitions + # to be described. You can pass as many as 25 identifiers in a + # single call to DescribeObjects. + # * Options <~Hash> - A Hash of additional options desrcibed in the API docs. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_objects(id, objectIds, options={}) + params = options.merge({ + 'pipelineId' => id, + 'objectIds' => objectIds, + }) + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.DescribeObjects' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def describe_objects(id, objects, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/describe_pipelines.rb b/lib/fog/aws/requests/data_pipeline/describe_pipelines.rb new file mode 100644 index 000000000..8316c7522 --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/describe_pipelines.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class DataPipeline + class Real + # Describe pipelines + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_DescribePipelines.html + # ==== Parameters + # * PipelineIds <~String> - ID of pipeline to retrieve information for + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_pipelines(ids) + params = {} + params['pipelineIds'] = ids + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.DescribePipelines' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def describe_pipelines(ids) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/get_pipeline_definition.rb b/lib/fog/aws/requests/data_pipeline/get_pipeline_definition.rb new file mode 100644 index 000000000..21da55b1b --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/get_pipeline_definition.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class DataPipeline + class Real + # Get pipeline definition JSON + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_GetPipelineDefinition.html + # ==== Parameters + # * PipelineId <~String> - The ID of the pipeline + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def get_pipeline_definition(id) + params = { + 'pipelineId' => id, + } + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.GetPipelineDefinition' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def get_pipeline_definition(id, objects) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/list_pipelines.rb b/lib/fog/aws/requests/data_pipeline/list_pipelines.rb new file mode 100644 index 000000000..30259ad9f --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/list_pipelines.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class DataPipeline + class Real + # List all pipelines + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_ListPipelines.html + # ==== Parameters + # * Marker <~String> - The starting point for the results to be returned. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def list_pipelines(options={}) + params = {} + params['Marker'] = options[:marker] if options[:marker] + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.ListPipelines' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def list_pipelines(options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/put_pipeline_definition.rb b/lib/fog/aws/requests/data_pipeline/put_pipeline_definition.rb new file mode 100644 index 000000000..e06e8c55a --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/put_pipeline_definition.rb @@ -0,0 +1,76 @@ +module Fog + module AWS + class DataPipeline + class Real + # Put raw pipeline definition JSON + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_PutPipelineDefinition.html + # ==== Parameters + # * PipelineId <~String> - The ID of the pipeline + # * PipelineObjects <~String> - Objects in the pipeline + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def put_pipeline_definition(id, objects) + params = { + 'pipelineId' => id, + 'pipelineObjects' => transform_objects(objects), + } + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.PutPipelineDefinition' }, + }) + + Fog::JSON.decode(response.body) + end + + # Take a list of pipeline object hashes as specified in the Data Pipeline JSON format + # and transform it into the format expected by the API + def transform_objects(objects) + objects.map { |object| JSONObject.new(object).to_api } + end + + class JSONObject + def initialize(object) + @json_fields = object.clone + @id = @json_fields.delete('id') + @name = @json_fields.delete('name') || @id + end + + def to_api + { + 'id' => @id, + 'name' => @name, + 'fields' => fields + } + end + + private + + def fields + @json_fields.map{|k,v| field_for_kv(k,v)}.flatten + end + + def field_for_kv(key, value) + if value.is_a?(Hash) + { 'key' => key, 'refValue' => value['ref'] } + + elsif value.is_a?(Array) + value.map { |subvalue| field_for_kv(key, subvalue) } + + else + { 'key' => key, 'stringValue' => value } + + end + end + end + end + + class Mock + def put_pipeline_definition(id, objects) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/data_pipeline/query_objects.rb b/lib/fog/aws/requests/data_pipeline/query_objects.rb new file mode 100644 index 000000000..a1a8ba94b --- /dev/null +++ b/lib/fog/aws/requests/data_pipeline/query_objects.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class DataPipeline + class Real + # Queries a pipeline for the names of objects that match a specified set of conditions. + # http://docs.aws.amazon.com/datapipeline/latest/APIReference/API_QueryObjects.html + # ==== Parameters + # * PipelineId <~String> - The ID of the pipeline + # * Sphere <~String> - Specifies whether the query applies to components or instances. + # Allowable values: COMPONENT, INSTANCE, ATTEMPT. + # * Marker <~String> - The starting point for the results to be returned. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def query_objects(id, sphere, options={}) + params = { + 'pipelineId' => id, + 'sphere' => sphere, + } + params['marker'] = options[:marker] if options[:marker] + + response = request({ + :body => Fog::JSON.encode(params), + :headers => { 'X-Amz-Target' => 'DataPipeline.QueryObjects' }, + }) + + Fog::JSON.decode(response.body) + end + end + + class Mock + def query_objects(id, sphere, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/change_resource_record_sets.rb b/lib/fog/aws/requests/dns/change_resource_record_sets.rb new file mode 100644 index 000000000..cdeb6ed2b --- /dev/null +++ b/lib/fog/aws/requests/dns/change_resource_record_sets.rb @@ -0,0 +1,243 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/change_resource_record_sets' + + # Use this action to create or change your authoritative DNS information for a zone + # http://docs.amazonwebservices.com/Route53/latest/DeveloperGuide/RRSchanges.html#RRSchanges_API + # + # ==== Parameters + # * zone_id<~String> - ID of the zone these changes apply to + # * options<~Hash> + # * comment<~String> - Any comments you want to include about the change. + # * change_batch<~Array> - The information for a change request + # * changes<~Hash> - + # * action<~String> - 'CREATE' or 'DELETE' + # * name<~String> - This must be a fully-specified name, ending with a final period + # * type<~String> - A | AAAA | CNAME | MX | NS | PTR | SOA | SPF | SRV | TXT + # * ttl<~Integer> - Time-to-live value - omit if using an alias record + # * weight<~Integer> - Time-to-live value - omit if using an alias record + # * set_identifier<~String> - An identifier that differentiates among multiple resource record sets that have the same combination of DNS name and type. + # * region<~String> - The Amazon EC2 region where the resource that is specified in this resource record set resides. (Latency only) + # * failover<~String> - To configure failover, you add the Failover element to two resource record sets. For one resource record set, you specify PRIMARY as the value for Failover; for the other resource record set, you specify SECONDARY. + # * geo_location<~String XML> - A complex type currently requiring XML that lets you control how Amazon Route 53 responds to DNS queries based on the geographic origin of the query. + # * health_check_id<~String> - If you want Amazon Route 53 to return this resource record set in response to a DNS query only when a health check is passing, include the HealthCheckId element and specify the ID of the applicable health check. + # * resource_records<~Array> - Omit if using an alias record + # * alias_target<~Hash> - Information about the domain to which you are redirecting traffic (Alias record sets only) + # * dns_name<~String> - The Elastic Load Balancing domain to which you want to reroute traffic + # * hosted_zone_id<~String> - The ID of the hosted zone that contains the Elastic Load Balancing domain to which you want to reroute traffic + # * evaluate_target_health<~Boolean> - Applies only to alias, weighted alias, latency alias, and failover alias resource record sets: If you set the value of EvaluateTargetHealth to true, the alias resource record sets inherit the health of the referenced resource record sets. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ChangeInfo'<~Hash> + # * 'Id'<~String> - The ID of the request + # * 'Status'<~String> - status of the request - PENDING | INSYNC + # * 'SubmittedAt'<~String> - The date and time the change was made + # * status<~Integer> - 200 when successful + # + # ==== Examples + # + # Example changing a CNAME record: + # + # change_batch_options = [ + # { + # :action => "DELETE", + # :name => "foo.example.com.", + # :type => "CNAME", + # :ttl => 3600, + # :resource_records => [ "baz.example.com." ] + # }, + # { + # :action => "CREATE", + # :name => "foo.example.com.", + # :type => "CNAME", + # :ttl => 3600, + # :resource_records => [ "bar.example.com." ] + # } + # ] + # + # change_resource_record_sets("ABCDEFGHIJKLMN", change_batch_options) + # + def change_resource_record_sets(zone_id, change_batch, options = {}) + # Aws methods return zone_ids that looks like '/hostedzone/id'. Let the caller either use + # that form or just the actual id (which is what this request needs) + zone_id = zone_id.sub('/hostedzone/', '') + + optional_tags = '' + options.each do |option, value| + case option + when :comment + optional_tags += "#{value}" + end + end + + #build XML + if change_batch.count > 0 + + changes = "#{optional_tags}" + + change_batch.each do |change_item| + action_tag = %Q{#{change_item[:action]}} + name_tag = %Q{#{change_item[:name]}} + type_tag = %Q{#{change_item[:type]}} + + # TTL must be omitted if using an alias record + ttl_tag = '' + ttl_tag += %Q{#{change_item[:ttl]}} unless change_item[:alias_target] + + weight_tag = '' + set_identifier_tag = '' + region_tag = '' + if change_item[:set_identifier] + set_identifier_tag += %Q{#{change_item[:set_identifier]}} + if change_item[:weight] # Weighted Record + weight_tag += %Q{#{change_item[:weight]}} + elsif change_item[:region] # Latency record + region_tag += %Q{#{change_item[:region]}} + end + end + + failover_tag = if change_item[:failover] + %Q{#{change_item[:failover]}} + end + + geolocation_tag = if change_item[:geo_location] + %Q{#{change_item[:geo_location]}} + end + + resource_records = change_item[:resource_records] || [] + resource_record_tags = '' + resource_records.each do |record| + resource_record_tags += %Q{#{record}} + end + + # ResourceRecords must be omitted if using an alias record + resource_tag = '' + resource_tag += %Q{#{resource_record_tags}} if resource_records.any? + + alias_target_tag = '' + if change_item[:alias_target] + # Accept either underscore or camel case for hash keys. + dns_name = change_item[:alias_target][:dns_name] || change_item[:alias_target][:DNSName] + hosted_zone_id = change_item[:alias_target][:hosted_zone_id] || change_item[:alias_target][:HostedZoneId] || Aws.hosted_zone_for_alias_target(dns_name) + evaluate_target_health = change_item[:alias_target][:evaluate_target_health] || change_item[:alias_target][:EvaluateTargetHealth] || false + evaluate_target_health_xml = !evaluate_target_health.nil? ? %Q{#{evaluate_target_health}} : '' + alias_target_tag += %Q{#{hosted_zone_id}#{dns_name}#{evaluate_target_health_xml}} + end + + health_check_id_tag = if change_item[:health_check_id] + %Q{#{change_item[:health_check_id]}} + end + + change_tags = %Q{#{action_tag}#{name_tag}#{type_tag}#{set_identifier_tag}#{weight_tag}#{region_tag}#{failover_tag}#{geolocation_tag}#{ttl_tag}#{resource_tag}#{alias_target_tag}#{health_check_id_tag}} + changes += change_tags + end + + changes += '' + end + + body = %Q{#{changes}} + request({ + :body => body, + :parser => Fog::Parsers::DNS::AWS::ChangeResourceRecordSets.new, + :expects => 200, + :method => 'POST', + :path => "hostedzone/#{zone_id}/rrset" + }) + end + end + + class Mock + def change_resource_record_sets(zone_id, change_batch, options = {}) + response = Excon::Response.new + errors = [] + + if (zone = self.data[:zones][zone_id]) + response.status = 200 + + change_id = Fog::AWS::Mock.change_id + change_batch.each do |change| + case change[:action] + when "CREATE" + if zone[:records][change[:type]].nil? + zone[:records][change[:type]] = {} + end + + if zone[:records][change[:type]][change[:name]].nil? + # raise change.to_s if change[:resource_records].nil? + zone[:records][change[:type]][change[:name]] = + if change[:alias_target] + record = { + :alias_target => change[:alias_target] + } + else + record = { + :ttl => change[:ttl].to_s, + } + end + zone[:records][change[:type]][change[:name]] = { + :change_id => change_id, + :resource_records => change[:resource_records] || [], + :name => change[:name], + :type => change[:type] + }.merge(record) + else + errors << "Tried to create resource record set #{change[:name]}. type #{change[:type]}, but it already exists" + end + when "DELETE" + if zone[:records][change[:type]].nil? || zone[:records][change[:type]].delete(change[:name]).nil? + errors << "Tried to delete resource record set #{change[:name]}. type #{change[:type]}, but it was not found" + end + end + end + + if errors.empty? + change = { + :id => change_id, + :status => 'PENDING', + :submitted_at => Time.now.utc.iso8601 + } + self.data[:changes][change[:id]] = change + response.body = { + 'Id' => change[:id], + 'Status' => change[:status], + 'SubmittedAt' => change[:submitted_at] + } + response + else + response.status = 400 + response.body = "#{errors.map {|e| "#{e}"}.join()}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + else + response.status = 404 + response.body = "NoSuchHostedZoneA hosted zone with the specified hosted zone ID does not exist.#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + + def self.hosted_zone_for_alias_target(dns_name) + k = elb_hosted_zone_mapping.keys.find do |k| + dns_name =~ /\A.+\.#{k}\.elb\.amazonaws\.com\.?\z/ + end + elb_hosted_zone_mapping[k] + end + + def self.elb_hosted_zone_mapping + @elb_hosted_zone_mapping ||= { + "ap-northeast-1" => "Z2YN17T5R711GT", + "ap-southeast-1" => "Z1WI8VXHPB1R38", + "ap-southeast-2" => "Z2999QAZ9SRTIC", + "eu-west-1" => "Z3NF1Z3NOM5OY2", + "sa-east-1" => "Z2ES78Y61JGQKS", + "us-east-1" => "Z3DZXE0Q79N41H", + "us-west-1" => "Z1M58G0W56PQJA", + "us-west-2" => "Z33MTJ483KN6FU", + } + end + end + end +end diff --git a/lib/fog/aws/requests/dns/create_health_check.rb b/lib/fog/aws/requests/dns/create_health_check.rb new file mode 100644 index 000000000..c1458744b --- /dev/null +++ b/lib/fog/aws/requests/dns/create_health_check.rb @@ -0,0 +1,64 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/health_check' + + # This action creates a new health check. + # http://docs.aws.amazon.com/Route53/latest/APIReference/API_CreateHealthCheck.html + # + # ==== Parameters (options as symbols Hash) + # * ip_address<~String> - (optional if fqdn) The IPv4 IP address of the endpoint on which you want Amazon Route 53 to perform health checks + # * port<~Integer> - The port on the endpoint on which you want Amazon Route 53 to perform health checks + # * type<~String> - HTTP | HTTPS | HTTP_STR_MATCH | HTTPS_STR_MATCH | TCP + # * resource_path<~Stringy> - (required for all types except TCP) The path that you want Amazon Route 53 to request when performing health checks. The path can be any value for which your endpoint will return an HTTP status code of 2xx or 3xx when the endpoint is healthy + # * fqdn<~String> - (optional if ip_address) The value that you want Amazon Route 53 to pass in the Host header in all health checks except TCP health checks + # * search_string<~String> - If the value of Type is HTTP_STR_MATCH or HTTP_STR_MATCH, the string that you want Amazon Route 53 to search for in the response body from the specified resource + # * request_interval<~String> - 10 | 30 (optional) The number of seconds between the time that Amazon Route 53 gets a response from your endpoint and the time that it sends the next health-check request + # * failure_threshold<~Integer> - 1-10 (optional) The number of consecutive health checks that an endpoint must pass or fail for Amazon Route 53 to change the current status of the endpoint from unhealthy to healthy or vice versa + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'HealthCheck'<~Hash> + # * 'Id'<~String> - The ID of the request + # * 'CallerReference'<~String> - A unique string that identifies the request and that allows failed CreateHealthCheck requests to be retried without the risk of executing the operation twice. + # * 'HealthCheckConfig'<~Hash> + # * 'IPAddress' + # * 'Port' + # * 'Type' + # * 'ResourcePath' + # * 'FullyQualifiedDomainName' + # * 'RequestInterval' + # * 'FailureThreshold' + # * status<~Integer> - 201 when successful + + def create_health_check(ip_address, port, type, options = {}) + version = @version + builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml| + xml.CreateHealthCheckRequest(:xmlns => "https://route53.amazonaws.com/doc/#{version}/") do + xml.CallerReference options[:caller_reference] || "#{Time.now.to_i.to_s}-#{SecureRandom.hex(6)}" + xml.HealthCheckConfig do + xml.IPAddress ip_address unless ip_address.nil? + xml.Port port + xml.Type type + xml.ResourcePath options[:resource_path] if options.has_key?(:resource_path) + xml.FullyQualifiedDomainName options[:fqdn] if options.has_key?(:fqdn) + xml.SearchString options[:search_string] if options.has_key?(:search_string) + xml.RequestInterval options[:request_interval] if options.has_key?(:request_interval) + xml.FailureThreshold options[:failure_threshold] if options.has_key?(:failure_threshold) + end + end + end + + request({ + :body => builder.to_xml.to_s, + :expects => 201, + :method => 'POST', + :path => 'healthcheck', + :parser => Fog::Parsers::DNS::AWS::HealthCheck.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/create_hosted_zone.rb b/lib/fog/aws/requests/dns/create_hosted_zone.rb new file mode 100644 index 000000000..3f7c06e00 --- /dev/null +++ b/lib/fog/aws/requests/dns/create_hosted_zone.rb @@ -0,0 +1,108 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/create_hosted_zone' + + # Creates a new hosted zone + # + # ==== Parameters + # * name<~String> - The name of the domain. Must be a fully-specified domain that ends with a period + # * options<~Hash> + # * caller_ref<~String> - unique string that identifies the request & allows failed + # calls to be retried without the risk of executing the operation twice + # * comment<~String> - + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'HostedZone'<~Hash>: + # * 'Id'<~String> - + # * 'Name'<~String> - + # * 'CallerReference'<~String> + # * 'Comment'<~String> - + # * 'ChangeInfo'<~Hash> - + # * 'Id'<~String> + # * 'Status'<~String> + # * 'SubmittedAt'<~String> + # * 'NameServers'<~Array> + # * 'NameServer'<~String> + # * status<~Integer> - 201 when successful + def create_hosted_zone(name, options = {}) + optional_tags = '' + if options[:caller_ref] + optional_tags += "#{options[:caller_ref]}" + else + #make sure we have a unique call reference + caller_ref = "ref-#{rand(1000000).to_s}" + optional_tags += "#{caller_ref}" + end + if options[:comment] + optional_tags += "#{options[:comment]}" + end + + request({ + :body => %Q{#{name}#{optional_tags}}, + :parser => Fog::Parsers::DNS::AWS::CreateHostedZone.new, + :expects => 201, + :method => 'POST', + :path => "hostedzone" + }) + end + end + + class Mock + require 'time' + + def create_hosted_zone(name, options = {}) + # Append a trailing period to the name if absent. + name = name + "." unless name.end_with?(".") + + response = Excon::Response.new + if list_hosted_zones.body['HostedZones'].select {|z| z['Name'] == name}.size < self.data[:limits][:duplicate_domains] + response.status = 201 + if options[:caller_ref] + caller_ref = options[:caller_ref] + else + #make sure we have a unique call reference + caller_ref = "ref-#{rand(1000000).to_s}" + end + zone_id = "/hostedzone/#{Fog::AWS::Mock.zone_id}" + self.data[:zones][zone_id] = { + :id => zone_id, + :name => name, + :reference => caller_ref, + :comment => options[:comment], + :records => {} + } + change = { + :id => Fog::AWS::Mock.change_id, + :status => 'PENDING', + :submitted_at => Time.now.utc.iso8601 + } + self.data[:changes][change[:id]] = change + response.body = { + 'HostedZone' => { + 'Id' => zone_id, + 'Name' => name, + 'CallerReference' => caller_ref, + 'Comment' => options[:comment] + }, + 'ChangeInfo' => { + 'Id' => change[:id], + 'Status' => change[:status], + 'SubmittedAt' => change[:submitted_at] + }, + 'NameServers' => Fog::AWS::Mock.nameservers + } + response + else + response.status = 400 + response.body = "DelegationSetNotAvailableAmazon Route 53 allows some duplication, but Amazon Route 53 has a maximum threshold of duplicated domains. This error is generated when you reach that threshold. In this case, the error indicates that too many hosted zones with the given domain name exist. If you want to create a hosted zone and Amazon Route 53 generates this error, contact Customer Support.#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/delete_health_check.rb b/lib/fog/aws/requests/dns/delete_health_check.rb new file mode 100644 index 000000000..b1accc629 --- /dev/null +++ b/lib/fog/aws/requests/dns/delete_health_check.rb @@ -0,0 +1,24 @@ +module Fog + module DNS + class Aws + class Real + # This action deletes a health check. + # http://docs.aws.amazon.com/Route53/latest/APIReference/API_DeleteHealthCheck.html + # + # ==== Parameters + # * id<~String> - Health check ID + # === Returns + # * response<~Excon::Response>: + # * status<~Integer> - 200 when successful + + def delete_health_check(id) + request({ + :expects => 200, + :method => 'DELETE', + :path => "healthcheck/#{id}" + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/delete_hosted_zone.rb b/lib/fog/aws/requests/dns/delete_hosted_zone.rb new file mode 100644 index 000000000..60745a478 --- /dev/null +++ b/lib/fog/aws/requests/dns/delete_hosted_zone.rb @@ -0,0 +1,66 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/delete_hosted_zone' + + # Delete a hosted zone + # + # ==== Parameters + # * zone_id<~String> - + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ChangeInfo'<~Hash> - + # * 'Id'<~String> The ID of the request + # * 'Status'<~String> The current state of the hosted zone + # * 'SubmittedAt'<~String> The date and time the change was made + # * status<~Integer> - 200 when successful + def delete_hosted_zone(zone_id) + # Aws methods return zone_ids that looks like '/hostedzone/id'. Let the caller either use + # that form or just the actual id (which is what this request needs) + zone_id = zone_id.sub('/hostedzone/', '') + + request({ + :expects => 200, + :parser => Fog::Parsers::DNS::AWS::DeleteHostedZone.new, + :method => 'DELETE', + :path => "hostedzone/#{zone_id}" + }) + end + end + + class Mock + require 'time' + + def delete_hosted_zone(zone_id) + response = Excon::Response.new + key = [zone_id, "/hostedzone/#{zone_id}"].find{|k| !self.data[:zones][k].nil?} + if key + change = { + :id => Fog::AWS::Mock.change_id, + :status => 'INSYNC', + :submitted_at => Time.now.utc.iso8601 + } + self.data[:changes][change[:id]] = change + response.status = 200 + response.body = { + 'ChangeInfo' => { + 'Id' => change[:id], + 'Status' => change[:status], + 'SubmittedAt' => change[:submitted_at] + } + } + self.data[:zones].delete(key) + response + else + response.status = 404 + response.body = "SenderNoSuchHostedZoneThe specified hosted zone does not exist.#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/get_change.rb b/lib/fog/aws/requests/dns/get_change.rb new file mode 100644 index 000000000..c9d608a8e --- /dev/null +++ b/lib/fog/aws/requests/dns/get_change.rb @@ -0,0 +1,59 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/get_change' + + # returns the current state of a change request + # + # ==== Parameters + # * change_id<~String> + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Id'<~String> + # * 'Status'<~String> + # * 'SubmittedAt'<~String> + # * status<~Integer> - 200 when successful + def get_change(change_id) + # Aws methods return change_ids that looks like '/change/id'. Let the caller either use + # that form or just the actual id (which is what this request needs) + change_id = change_id.sub('/change/', '') + + request({ + :expects => 200, + :parser => Fog::Parsers::DNS::AWS::GetChange.new, + :method => 'GET', + :path => "change/#{change_id}" + }) + end + end + + class Mock + def get_change(change_id) + response = Excon::Response.new + # find the record with matching change_id + # records = data[:zones].values.map{|z| z[:records].values.map{|r| r.values}}.flatten + change = self.data[:changes][change_id] + + if change + response.status = 200 + submitted_at = Time.parse(change[:submitted_at]) + response.body = { + 'Id' => change[:id], + # set as insync after some time + 'Status' => (submitted_at + Fog::Mock.delay) < Time.now ? 'INSYNC' : change[:status], + 'SubmittedAt' => change[:submitted_at] + } + response + else + response.status = 404 + response.body = "SenderNoSuchChangeCould not find resource with ID: #{change_id}#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/get_health_check.rb b/lib/fog/aws/requests/dns/get_health_check.rb new file mode 100644 index 000000000..e1e6995b8 --- /dev/null +++ b/lib/fog/aws/requests/dns/get_health_check.rb @@ -0,0 +1,41 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/health_check' + + # This action gets information about a specified health check. + #http://docs.aws.amazon.com/Route53/latest/APIReference/API_GetHealthCheck.html + # + # ==== Parameters + # * id<~String> - The ID of the health check + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'HealthCheck'<~Hash>: + # * 'Id'<~String> - + # * 'CallerReference'<~String> + # * 'HealthCheckConfig'<~Hash>: + # * 'IPAddress'<~String> - + # * 'Port'<~String> - + # * 'Type'<~String> - + # * 'ResourcePath'<~String> - + # * 'FullyQualifiedDomainName'<~String> - + # * 'SearchString'<~String> - + # * 'RequestInterval'<~Integer> - + # * 'FailureThreshold'<~String> - + # * 'HealthCheckVersion'<~Integer> - + # * status<~Integer> - 200 when successful + def get_health_check(id) + request({ + :expects => 200, + :parser => Fog::Parsers::DNS::AWS::HealthCheck.new, + :method => 'GET', + :path => "healthcheck/#{id}" + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/get_hosted_zone.rb b/lib/fog/aws/requests/dns/get_hosted_zone.rb new file mode 100644 index 000000000..3cefd0b9a --- /dev/null +++ b/lib/fog/aws/requests/dns/get_hosted_zone.rb @@ -0,0 +1,61 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/get_hosted_zone' + + # retrieve information about a hosted zone + # + # ==== Parameters + # * zone_id<~String> - The ID of the hosted zone + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'HostedZone'<~Hash>: + # * 'Id'<~String> - + # * 'Name'<~String> - + # * 'CallerReference'<~String> + # * 'Comment'<~String> - + # * 'NameServers'<~Array> + # * 'NameServer'<~String> + # * status<~Integer> - 200 when successful + def get_hosted_zone(zone_id) + # Aws methods return zone_ids that looks like '/hostedzone/id'. Let the caller either use + # that form or just the actual id (which is what this request needs) + zone_id = zone_id.sub('/hostedzone/', '') + + request({ + :expects => 200, + :parser => Fog::Parsers::DNS::AWS::GetHostedZone.new, + :method => 'GET', + :path => "hostedzone/#{zone_id}" + }) + end + end + + class Mock + def get_hosted_zone(zone_id) + response = Excon::Response.new + if (zone = self.data[:zones][zone_id]) + response.status = 200 + response.body = { + 'HostedZone' => { + 'Id' => zone[:id], + 'Name' => zone[:name], + 'CallerReference' => zone[:reference], + 'Comment' => zone[:comment] + }, + 'NameServers' => Fog::AWS::Mock.nameservers + } + response + else + response.status = 404 + response.body = "SenderNoSuchHostedZoneThe specified hosted zone does not exist.#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/list_health_checks.rb b/lib/fog/aws/requests/dns/list_health_checks.rb new file mode 100644 index 000000000..b2e021508 --- /dev/null +++ b/lib/fog/aws/requests/dns/list_health_checks.rb @@ -0,0 +1,36 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/list_health_checks' + + # This action gets a list of the health checks that are associated with the current Aws account. + # http://docs.aws.amazon.com/Route53/latest/APIReference/API_ListHealthChecks.html + # + # === Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'HealthChecks'<~Array>: + # * 'HealthCheck'<~Hash>: + # * 'Id'<~String> - + # * 'CallerReference'<~String> + # * 'HealthCheckVersion'<~Integer> - + # * 'Marker'<~String> - + # * 'MaxItems'<~Integer> - + # * 'IsTruncated'<~String> - + # * 'NextMarker'<~String> + # * status<~Integer> - 200 when successful + + def list_health_checks + request({ + :expects => 200, + :method => 'GET', + :path => "healthcheck", + :parser => Fog::Parsers::DNS::AWS::ListHealthChecks.new + }) + end + end + end + end +end + diff --git a/lib/fog/aws/requests/dns/list_hosted_zones.rb b/lib/fog/aws/requests/dns/list_hosted_zones.rb new file mode 100644 index 000000000..013e42611 --- /dev/null +++ b/lib/fog/aws/requests/dns/list_hosted_zones.rb @@ -0,0 +1,88 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/list_hosted_zones' + + # Describe all or specified instances + # + # ==== Parameters + # * options<~Hash> + # * marker<~String> - Indicates where to begin in your list of hosted zones. + # * max_items<~Integer> - The maximum number of hosted zones to be included in the response body + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'HostedZones'<~Array>: + # * 'HostedZone'<~Hash>: + # * 'Id'<~String> - + # * 'Name'<~String> - + # * 'CallerReference'<~String> + # * 'Comment'<~String> - + # * 'Marker'<~String> - + # * 'MaxItems'<~Integer> - + # * 'IsTruncated'<~String> - + # * 'NextMarker'<~String> + # * status<~Integer> - 200 when successful + def list_hosted_zones(options = {}) + parameters = {} + options.each do |option, value| + case option + when :marker + parameters[option] = value + when :max_items + parameters[:maxitems] = value + end + end + + request({ + :query => parameters, + :parser => Fog::Parsers::DNS::AWS::ListHostedZones.new, + :expects => 200, + :method => 'GET', + :path => "hostedzone" + }) + end + end + + class Mock + def list_hosted_zones(options = {}) + maxitems = [options[:max_items]||100,100].min + + if options[:marker].nil? + start = 0 + else + start = self.data[:zones].find_index {|z| z[:id] == options[:marker]} + end + + zones = self.data[:zones].values[start, maxitems] + next_zone = self.data[:zones].values[start + maxitems] + truncated = !next_zone.nil? + + response = Excon::Response.new + response.status = 200 + response.body = { + 'HostedZones' => zones.map do |z| + { + 'Id' => z[:id], + 'Name' => z[:name], + 'CallerReference' => z[:reference], + 'Comment' => z[:comment], + } + end, + 'Marker' => options[:marker].to_s, + 'MaxItems' => maxitems, + 'IsTruncated' => truncated + } + + if truncated + response.body['NextMarker'] = next_zone[:id] + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/dns/list_resource_record_sets.rb b/lib/fog/aws/requests/dns/list_resource_record_sets.rb new file mode 100644 index 000000000..a2b1c84c0 --- /dev/null +++ b/lib/fog/aws/requests/dns/list_resource_record_sets.rb @@ -0,0 +1,130 @@ +module Fog + module DNS + class Aws + class Real + require 'fog/aws/parsers/dns/list_resource_record_sets' + + # list your resource record sets + # + # ==== Parameters + # * zone_id<~String> - + # * options<~Hash> + # * type<~String> - + # * name<~String> - + # * identifier<~String> - + # * max_items<~Integer> - + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResourceRecordSet'<~Array>: + # * 'Name'<~String> - + # * 'Type'<~String> - + # * 'TTL'<~Integer> - + # * 'AliasTarget'<~Hash> - + # * 'HostedZoneId'<~String> - + # * 'DNSName'<~String> - + # * 'ResourceRecords'<~Array> + # * 'Value'<~String> - + # * 'IsTruncated'<~String> - + # * 'MaxItems'<~String> - + # * 'NextRecordName'<~String> + # * 'NextRecordType'<~String> + # * 'NextRecordIdentifier'<~String> + # * status<~Integer> - 201 when successful + def list_resource_record_sets(zone_id, options = {}) + # Aws methods return zone_ids that looks like '/hostedzone/id'. Let the caller either use + # that form or just the actual id (which is what this request needs) + zone_id = zone_id.sub('/hostedzone/', '') + + parameters = {} + options.each do |option, value| + case option + when :type, :name, :identifier + parameters[option] = "#{value}" + when :max_items + parameters['maxitems'] = "#{value}" + end + end + + request({ + :query => parameters, + :parser => Fog::Parsers::DNS::AWS::ListResourceRecordSets.new, + :expects => 200, + :method => 'GET', + :path => "hostedzone/#{zone_id}/rrset" + }) + end + end + + class Mock + def list_resource_record_sets(zone_id, options = {}) + maxitems = [options[:max_items]||100,100].min + + response = Excon::Response.new + + zone = self.data[:zones][zone_id] + if zone.nil? + response.status = 404 + response.body = "\nSenderNoSuchHostedZoneNo hosted zone found with ID: #{zone_id}#{Fog::AWS::Mock.request_id}" + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + records = if options[:type] + records_type = zone[:records][options[:type]] + records_type.values if records_type + else + zone[:records].values.map{|r| r.values}.flatten + end + + records ||= [] + + # sort for pagination + records.sort! { |a,b| a[:name].gsub(zone[:name],"") <=> b[:name].gsub(zone[:name],"") } + + if options[:name] + name = options[:name].gsub(zone[:name],"") + records = records.select{|r| r[:name].gsub(zone[:name],"") >= name } + require 'pp' + end + + next_record = records[maxitems] + records = records[0, maxitems] + truncated = !next_record.nil? + + response.status = 200 + response.body = { + 'ResourceRecordSets' => records.map do |r| + if r[:alias_target] + record = { + 'AliasTarget' => { + 'HostedZoneId' => r[:alias_target][:hosted_zone_id], + 'DNSName' => r[:alias_target][:dns_name] + } + } + else + record = { + 'TTL' => r[:ttl] + } + end + { + 'ResourceRecords' => r[:resource_records], + 'Name' => r[:name], + 'Type' => r[:type] + }.merge(record) + end, + 'MaxItems' => maxitems, + 'IsTruncated' => truncated + } + + if truncated + response.body['NextRecordName'] = next_record[:name] + response.body['NextRecordType'] = next_record[:type] + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/batch_get_item.rb b/lib/fog/aws/requests/dynamodb/batch_get_item.rb new file mode 100644 index 000000000..f97899d66 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/batch_get_item.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class DynamoDB + class Real + # Get DynamoDB items + # + # ==== Parameters + # * 'request_items'<~Hash>: + # * 'table_name'<~Hash>: + # * 'Keys'<~Array>: array of keys + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeType'<~String> - type of attribute + # * 'AttributeName'<~String> - name of attribute + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeType'<~String> - type of attribute + # * 'AttributeName'<~String> - name of attribute + # * 'AttributesToGet'<~Array> - optional attributes to return, defaults to all + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Responses'<~Hash>: + # * 'table_name'<~Hash>: + # * 'Items'<~Array> - Matching items + # * 'ConsumedCapacityUnits'<~Float> - Capacity units used in read + # * 'UnprocessedKeys':<~Hash> - tables and keys in excess of per request limit, pass this to subsequent batch get for pseudo-pagination + def batch_get_item(request_items) + body = { + 'RequestItems' => request_items + } + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.BatchGetItem'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/batch_write_item.rb b/lib/fog/aws/requests/dynamodb/batch_write_item.rb new file mode 100644 index 000000000..7cdae1470 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/batch_write_item.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class DynamoDB + class Real + def batch_put_item(request_items) + Fog::Logger.deprecation("batch_put_item is deprecated, use batch_write_item instead") + batch_write_item(request_items) + end + + #request_items has form: + #{"table_name"=> + # [{"PutRequest"=> + # {"Item"=> + # {"hash_key"=>{"N"=>"99"}, + # "range_key"=>{"N"=>"99"}, + # "attribute"=>{"S"=>"hi"} + # }}}, ... ]} + # For more information: + # http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/API_BatchWriteItems.html + def batch_write_item(request_items) + body = { + 'RequestItems' => request_items + } + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.BatchWriteItem'} + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/create_table.rb b/lib/fog/aws/requests/dynamodb/create_table.rb new file mode 100644 index 000000000..3252bf566 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/create_table.rb @@ -0,0 +1,53 @@ +module Fog + module AWS + class DynamoDB + class Real + # Create DynamoDB table + # + # ==== Parameters + # * 'table_name'<~String> - name of table to create + # * 'key_schema'<~Hash>: + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'provisioned_throughput'<~Hash>: + # * 'ReadCapacityUnits'<~Integer> - read capacity for table, in 5..10000 + # * 'WriteCapacityUnits'<~Integer> - write capacity for table, in 5..10000 + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'TableDescription'<~Hash> + # * 'CreationDateTime'<~Float> - Unix epoch time of table creation + # * 'KeySchema'<~Hash> - schema for table + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'ProvisionedThroughput'<~Hash>: + # * 'ReadCapacityUnits'<~Integer> - read capacity for table, in 5..10000 + # * 'WriteCapacityUnits'<~Integer> - write capacity for table, in 5..10000 + # * 'TableName'<~String> - name of table + # * 'TableStatus'<~String> - status of table + def create_table(table_name, key_schema, provisioned_throughput) + body = { + 'KeySchema' => key_schema, + 'ProvisionedThroughput' => provisioned_throughput, + 'TableName' => table_name + } + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.CreateTable'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/delete_item.rb b/lib/fog/aws/requests/dynamodb/delete_item.rb new file mode 100644 index 000000000..50d651721 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/delete_item.rb @@ -0,0 +1,43 @@ +module Fog + module AWS + class DynamoDB + class Real + # Delete DynamoDB item + # + # ==== Parameters + # * 'table_name'<~String> - name of table for item + # * 'key'<~Hash>: + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute + # * 'options'<~Hash>: + # * 'Expected'<~Hash>: data to check against + # * 'AttributeName'<~String> - name of attribute + # * 'Value'<~Hash> - a value to check for the value of + # or + # * 'Exists'<~Boolean> - set as false to only allow update if attribute doesn't exist + # * 'ReturnValues'<~String> - data to return in %w{ALL_NEW ALL_OLD NONE UPDATED_NEW UPDATED_OLD}, defaults to NONE + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # varies based on ReturnValues param, see: http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/API_UpdateItem.html + def delete_item(table_name, key, options = {}) + body = { + 'Key' => key, + 'TableName' => table_name + }.merge(options) + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.DeleteItem'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/delete_table.rb b/lib/fog/aws/requests/dynamodb/delete_table.rb new file mode 100644 index 000000000..19945ba8e --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/delete_table.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class DynamoDB + class Real + # Delete DynamoDB table + # + # ==== Parameters + # * 'table_name'<~String> - name of table to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'TableDescription'<~Hash> + # * 'KeySchema'<~Hash> - schema for table + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'ProvisionedThroughput'<~Hash>: + # * 'ReadCapacityUnits'<~Integer> - read capacity for table, in 5..10000 + # * 'WriteCapacityUnits'<~Integer> - write capacity for table, in 5..10000 + # * 'TableName'<~String> - name of table + # * 'TableStatus'<~String> - status of table + def delete_table(table_name) + body = { + 'TableName' => table_name + } + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.DeleteTable'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/describe_table.rb b/lib/fog/aws/requests/dynamodb/describe_table.rb new file mode 100644 index 000000000..8d9d794d1 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/describe_table.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class DynamoDB + class Real + # Describe DynamoDB table + # + # ==== Parameters + # * 'table_name'<~String> - name of table to describe + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Table'<~Hash> + # * 'CreationDateTime'<~Float> - Unix epoch time of table creation + # * 'KeySchema'<~Hash> - schema for table + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'ProvisionedThroughput'<~Hash>: + # * 'ReadCapacityUnits'<~Integer> - read capacity for table, in 5..10000 + # * 'WriteCapacityUnits'<~Integer> - write capacity for table, in 5..10000 + # * 'TableName'<~String> - name of table + # * 'TableSizeBytes'<~Integer> - size of table in bytes + # * 'TableStatus'<~String> - status of table + def describe_table(table_name) + body = { + 'TableName' => table_name + } + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.DescribeTable'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/get_item.rb b/lib/fog/aws/requests/dynamodb/get_item.rb new file mode 100644 index 000000000..376cf990a --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/get_item.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class DynamoDB + class Real + # Get DynamoDB item + # + # ==== Parameters + # * 'table_name'<~String> - name of table for item + # * 'key'<~Hash>: + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeType'<~String> - type of attribute + # * 'AttributeName'<~String> - name of attribute + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeType'<~String> - type of attribute + # * 'AttributeName'<~String> - name of attribute + # * 'options'<~Hash>: + # * 'AttributesToGet'<~Array>: list of array names to return, defaults to returning all + # * 'ConsistentRead'<~Boolean>: whether to wait for updates, defaults to false + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ConsumedCapacityUnits'<~Float> - Capacity units used in read + # * 'Item':<~Hash>: + # * 'AttributeName'<~Hash>: in form of {"type":value} + def get_item(table_name, key, options = {}) + body = { + 'Key' => key, + 'TableName' => table_name + }.merge(options) + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.GetItem'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/list_tables.rb b/lib/fog/aws/requests/dynamodb/list_tables.rb new file mode 100644 index 000000000..c9cf7ae00 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/list_tables.rb @@ -0,0 +1,27 @@ +module Fog + module AWS + class DynamoDB + class Real + # List DynamoDB tables + # + # ==== Parameters + # * 'options'<~Hash> - options, defaults to {} + # * 'ExclusiveStartTableName'<~String> - name of table to begin listing with + # * 'Limit'<~Integer> - limit number of tables to return + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'LastEvaluatedTableName'<~String> - last table name, for pagination + # * 'TableNames'<~Array> - table names + def list_tables(options = {}) + request( + :body => Fog::JSON.encode(options), + :headers => {'x-amz-target' => 'DynamoDB_20111205.ListTables'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/put_item.rb b/lib/fog/aws/requests/dynamodb/put_item.rb new file mode 100644 index 000000000..04c0eac94 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/put_item.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class DynamoDB + class Real + # Update DynamoDB item + # + # ==== Parameters + # * 'table_name'<~String> - name of table for item + # * 'item'<~Hash>: data to update, must include primary key + # * 'AttributeName'<~String> - Attribute to update + # * 'Value'<~Hash> - formated as {type => value} + # * 'Action'<~String> - action to take if expects matches, in %w{ADD DELETE PUT}, defaults to PUT + # * 'options'<~Hash>: + # * 'Expected'<~Hash>: data to check against + # * 'AttributeName'<~String> - name of attribute + # * 'Value'<~Hash> - a value to check for the value of + # or + # * 'Exists'<~Boolean> - set as false to only allow update if attribute doesn't exist + # * 'ReturnValues'<~String> - data to return in %w{ALL_NEW ALL_OLD NONE UPDATED_NEW UPDATED_OLD}, defaults to NONE + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # varies based on ReturnValues param, see: http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/API_UpdateItem.html + def put_item(table_name, item, options = {}) + body = { + 'Item' => item, + 'TableName' => table_name + }.merge(options) + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20120810.PutItem'} + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/query.rb b/lib/fog/aws/requests/dynamodb/query.rb new file mode 100644 index 000000000..ace8a528e --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/query.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class DynamoDB + class Real + # Query DynamoDB items + # + # ==== Parameters + # * 'table_name'<~String> - name of table to query + # * 'hash_key'<~Hash> - hash key to query + # * options<~Hash>: + # * 'AttributesToGet'<~Array> - Array of attributes to get for each item, defaults to all + # * 'ConsistentRead'<~Boolean> - Whether to wait for consistency, defaults to false + # * 'Count'<~Boolean> - If true, returns only a count of such items rather than items themselves, defaults to false + # * 'Limit'<~Integer> - limit of total items to return + # * 'RangeKeyCondition'<~Hash>: value to compare against range key + # * 'AttributeValueList'<~Hash>: one or more values to compare against + # * 'ComparisonOperator'<~String>: comparison operator to use with attribute value list, in %w{BETWEEN BEGINS_WITH EQ LE LT GE GT} + # * 'ScanIndexForward'<~Boolean>: Whether to scan from start or end of index, defaults to start + # * 'ExclusiveStartKey'<~Hash>: Key to start listing from, can be taken from LastEvaluatedKey in response + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ConsumedCapacityUnits'<~Integer> - number of capacity units used for query + # * 'Count'<~Integer> - number of items in response + # * 'Items'<~Array> - array of items returned + # * 'LastEvaluatedKey'<~Hash> - last key scanned, can be passed to ExclusiveStartKey for pagination + def query(table_name, hash_key, options = {}) + body = { + 'TableName' => table_name, + 'HashKeyValue' => hash_key + }.merge(options) + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.Query'} + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/scan.rb b/lib/fog/aws/requests/dynamodb/scan.rb new file mode 100644 index 000000000..cc4b76181 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/scan.rb @@ -0,0 +1,43 @@ +module Fog + module AWS + class DynamoDB + class Real + # Scan DynamoDB items + # + # ==== Parameters + # * 'table_name'<~String> - name of table to query + # * options<~Hash>: + # * 'AttributesToGet'<~Array> - Array of attributes to get for each item, defaults to all + # * 'ConsistentRead'<~Boolean> - Whether to wait for consistency, defaults to false + # * 'Count'<~Boolean> - If true, returns only a count of such items rather than items themselves, defaults to false + # * 'Limit'<~Integer> - limit of total items to return + # * 'ScanFilter'<~Hash>: value to compare against + # * attribute_name<~Hash>: + # * 'AttributeValueList'<~Hash>: one or more values to compare against + # * 'ComparisonOperator'<~String>: comparison operator to use with attribute value list, in %w{BETWEEN BEGINS_WITH EQ LE LT GE GT} + # * 'ScanIndexForward'<~Boolean>: Whether to scan from start or end of index, defaults to start + # * 'ExclusiveStartKey'<~Hash>: Key to start listing from, can be taken from LastEvaluatedKey in response + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ConsumedCapacityUnits'<~Integer> - number of capacity units used for scan + # * 'Count'<~Integer> - number of items in response + # * 'Items'<~Array> - array of items returned + # * 'LastEvaluatedKey'<~Hash> - last key scanned, can be passed to ExclusiveStartKey for pagination + # * 'ScannedCount'<~Integer> - number of items scanned before applying filters + def scan(table_name, options = {}) + body = { + 'TableName' => table_name + }.merge(options) + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.Scan'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/update_item.rb b/lib/fog/aws/requests/dynamodb/update_item.rb new file mode 100644 index 000000000..56140f261 --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/update_item.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class DynamoDB + class Real + # Update DynamoDB item + # + # ==== Parameters + # * 'table_name'<~String> - name of table for item + # * 'key'<~Hash>: + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute + # * 'attribute_updates'<~Hash>: + # * 'AttributeName'<~String> - Attribute to update + # * 'Value'<~Hash> - formated as {type => value} + # * 'Action'<~String> - action to take if expects matches, in %w{ADD DELETE PUT}, defaults to PUT + # * 'options'<~Hash>: + # * 'Expected'<~Hash>: data to check against + # * 'AttributeName'<~String> - name of attribute + # * 'Value'<~Hash> - a value to check for the value of + # or + # * 'Exists'<~Boolean> - set as false to only allow update if attribute doesn't exist + # * 'ReturnValues'<~String> - data to return in %w{ALL_NEW ALL_OLD NONE UPDATED_NEW UPDATED_OLD}, defaults to NONE + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # varies based on ReturnValues param, see: http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/API_UpdateItem.html + def update_item(table_name, key, attribute_updates, options = {}) + body = { + 'AttributeUpdates' => attribute_updates, + 'Key' => key, + 'TableName' => table_name + }.merge(options) + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.UpdateItem'} + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/dynamodb/update_table.rb b/lib/fog/aws/requests/dynamodb/update_table.rb new file mode 100644 index 000000000..658c9f90b --- /dev/null +++ b/lib/fog/aws/requests/dynamodb/update_table.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class DynamoDB + class Real + # Update DynamoDB table throughput + # + # ==== Parameters + # * 'table_name'<~String> - name of table to describe + # * 'provisioned_throughput'<~Hash>: + # * 'ReadCapacityUnits'<~Integer> - read capacity for table, in 5..10000 + # * 'WriteCapacityUnits'<~Integer> - write capacity for table, in 5..10000 + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Table'<~Hash> + # * 'KeySchema'<~Hash> - schema for table + # * 'HashKeyElement'<~Hash>: info for primary key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'RangeKeyElement'<~Hash>: optional, info for range key + # * 'AttributeName'<~String> - name of attribute + # * 'AttributeType'<~String> - type of attribute, in %w{N NS S SS} for number, number set, string, string set + # * 'ProvisionedThroughput'<~Hash>: + # * 'ReadCapacityUnits'<~Integer> - read capacity for table, in 5..10000 + # * 'WriteCapacityUnits'<~Integer> - write capacity for table, in 5..10000 + # * 'TableName'<~String> - name of table + # * 'TableStatus'<~String> - status of table + def update_table(table_name, provisioned_throughput) + body = { + 'ProvisionedThroughput' => provisioned_throughput, + 'TableName' => table_name + } + + request( + :body => Fog::JSON.encode(body), + :headers => {'x-amz-target' => 'DynamoDB_20111205.UpdateTable'}, + :idempotent => true + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/authorize_cache_security_group_ingress.rb b/lib/fog/aws/requests/elasticache/authorize_cache_security_group_ingress.rb new file mode 100644 index 000000000..93850a030 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/authorize_cache_security_group_ingress.rb @@ -0,0 +1,57 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_security_group' + + # Authorize ingress to a CacheSecurityGroup using EC2 Security Groups + # + # === Parameters + # * name <~String> - The name of the cache security group + # * ec2_name <~String> - The name of the EC2 security group to authorize + # * ec2_owner_id <~String> - The Aws Account Number of the EC2 security group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def authorize_cache_security_group_ingress(name, ec2_name, ec2_owner_id) + request({ + 'Action' => 'AuthorizeCacheSecurityGroupIngress', + 'CacheSecurityGroupName' => name, + 'EC2SecurityGroupName' => ec2_name, + 'EC2SecurityGroupOwnerId' => ec2_owner_id, + :parser => Fog::Parsers::AWS::Elasticache::SingleSecurityGroup.new + }) + end + end + + class Mock + def authorize_cache_security_group_ingress(name, ec2_name, ec2_owner_id) + opts = { + 'EC2SecurityGroupName' => ec2_name, + 'EC2SecurityGroupOwnerId' => ec2_owner_id + } + + if sec_group = self.data[:security_groups][name] + + if sec_group['EC2SecurityGroups'].find{|h| h['EC2SecurityGroupName'] == opts['EC2SecurityGroupName']} + raise Fog::AWS::Elasticache::AuthorizationAlreadyExists.new("AuthorizationAlreadyExists => #{opts['EC2SecurityGroupName']} is alreay defined") + end + sec_group['EC2SecurityGroups'] << opts.merge({'Status' => 'authorizing'}) + + Excon::Response.new( + { + :status => 200, + :body => { + 'ResponseMetadata'=>{ 'RequestId'=> Fog::AWS::Mock.request_id }, + 'CacheSecurityGroup' => sec_group + } + } + ) + else + raise Fog::AWS::Elasticache::NotFound.new("CacheSecurityGroupNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/create_cache_cluster.rb b/lib/fog/aws/requests/elasticache/create_cache_cluster.rb new file mode 100644 index 000000000..7fcf11517 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/create_cache_cluster.rb @@ -0,0 +1,94 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_cache_cluster' + # creates a cache cluster + # + # === Required Parameters + # * id <~String> - A unique cluster ID - 20 characters max. + # === Optional Parameters + # * options <~Hash> - All optional parameters should be set in this Hash: + # * :node_type <~String> - The size (flavor) of the cache Nodes + # * :security_group_names <~Array> - Array of Elasticache::SecurityGroup names + # * :vpc_security_groups <~Array> - Array + # * :num_nodes <~Integer> - The number of nodes in the Cluster + # * :auto_minor_version_upgrade <~TrueFalseClass> + # * :parameter_group_name <~String> - Name of the Cluster's ParameterGroup + # * :engine <~String> - The Cluster's caching software (memcached) + # * :engine_version <~String> - The Cluster's caching software version + # * :notification_topic_arn <~String> - Amazon SNS Resource Name + # * :port <~Integer> - The memcached port number + # * :preferred_availablility_zone <~String> + # * :preferred_maintenance_window <~String> + # * :cache_subnet_group_name <~String> + # * :s3_snapshot_location <~String> - Amazon resource location for snapshot + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def create_cache_cluster(id, options = {}) + req_options = { + 'Action' => 'CreateCacheCluster', + 'CacheClusterId' => id.strip, + 'CacheNodeType' => options[:node_type] || 'cache.m1.large', + 'Engine' => options[:engine] || 'memcached', + 'NumCacheNodes' => options[:num_nodes] || 1, + 'AutoMinorVersionUpgrade' => options[:auto_minor_version_upgrade], + 'CacheParameterGroupName' => options[:parameter_group_name], + 'CacheSubnetGroupName' => options[:cache_subnet_group_name], + 'EngineVersion' => options[:engine_version], + 'NotificationTopicArn' => options[:notification_topic_arn], + 'Port' => options[:port], + 'PreferredAvailabilityZone' => options[:preferred_availablility_zone], + 'PreferredMaintenanceWindow' => options[:preferred_maintenance_window], + :parser => Fog::Parsers::AWS::Elasticache::SingleCacheCluster.new + } + + if s3_snapshot_location = options.delete(:s3_snapshot_location) + req_options.merge!(Fog::AWS.indexed_param('SnapshotArns.member.%d', [*s3_snapshot_location])) + end + + if cache_security_groups = options.delete(:security_group_names) + req_options.merge!(Fog::AWS.indexed_param('CacheSecurityGroupNames.member.%d', [*cache_security_groups])) + end + + if vpc_security_groups = options.delete(:vpc_security_groups) + req_options.merge!(Fog::AWS.indexed_param('SecurityGroupIds.member.%d', [*vpc_security_groups])) + end + + request( req_options ) + end + end + + class Mock + def create_cache_cluster(id, options = {}) + response = Excon::Response.new + cluster = { # create an in-memory representation of this cluster + 'CacheClusterId' => id.strip, + 'NumCacheNodes' => options[:num_nodes] || 1, + 'CacheNodeType' => options[:node_type] || 'cache.m1.large', + 'Engine' => options[:engine] || 'memcached', + 'EngineVersion' => options[:engine_version] || '1.4.5', + 'CacheClusterStatus' => 'available', + 'CacheNodes' => create_cache_nodes(id.strip, options[:num_nodes]), + 'CacheSecurityGroups' => [], + 'CacheParameterGroup' => { 'CacheParameterGroupName' => + options[:parameter_group_name] || 'default.memcached1.4' }, + 'CacheSubnetGroupName' => options[:cache_subnet_group_name], + 'PendingModifiedValues' => {}, + 'AutoMinorVersionUpgrade' => + options[:auto_minor_version_upgrade] || 'true', + 'PreferredMaintenanceWindow' => + options[:preferred_maintenance_window] || 'sun:05:00-sun:09:00', + } + self.data[:clusters][id] = cluster # store the in-memory cluster + response.body = { + 'CacheCluster' => cluster.merge({'CacheClusterStatus' => 'creating'}), + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/create_cache_parameter_group.rb b/lib/fog/aws/requests/elasticache/create_cache_parameter_group.rb new file mode 100644 index 000000000..d6754c0a5 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/create_cache_parameter_group.rb @@ -0,0 +1,52 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_parameter_group' + + # creates a cache parameter group + # + # === Parameters + # * name <~String> - The name for the Cache Parameter Group + # === Optional Parameters + # * description <~String> - The description for the Cache Parameter Group + # * family <~String> - The description for the Cache Parameter Group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def create_cache_parameter_group(name, description = name, family = 'memcached1.4') + request({ + 'Action' => 'CreateCacheParameterGroup', + 'CacheParameterGroupName' => name, + 'Description' => description, + 'CacheParameterGroupFamily' => family, + :parser => Fog::Parsers::AWS::Elasticache::SingleParameterGroup.new + }) + end + end + + class Mock + def create_cache_parameter_group(name, description = name, family = 'memcached1.4') + response = Excon::Response.new + if self.data[:parameter_groups] and self.data[:parameter_groups][name] + raise Fog::AWS::Elasticache::IdentifierTaken.new("Parameter group #{name} already exists") + end + + data = { + 'CacheParameterGroupName' => name, + 'CacheParameterGroupFamily' => family.downcase, + 'Description' => description + } + self.data[:parameter_groups][name] = data + + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CreateCacheParameterGroupResult"=> {"CacheParameterGroup"=> data} + } + response.status = 200 + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/create_cache_security_group.rb b/lib/fog/aws/requests/elasticache/create_cache_security_group.rb new file mode 100644 index 000000000..8f30e1abd --- /dev/null +++ b/lib/fog/aws/requests/elasticache/create_cache_security_group.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_security_group' + + # creates a cache security group + # + # === Parameters + # * name <~String> - The name for the Cache Security Group + # * description <~String> - The description for the Cache Security Group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def create_cache_security_group(name, description = name) + request({ + 'Action' => 'CreateCacheSecurityGroup', + 'CacheSecurityGroupName' => name, + 'Description' => description, + :parser => Fog::Parsers::AWS::Elasticache::SingleSecurityGroup.new + }) + end + end + + class Mock + def create_cache_security_group(name, description = name) + if self.data[:security_groups][name] + raise Fog::AWS::Elasticache::IdentifierTaken.new("CacheClusterAlreadyExists => The security group '#{name}' already exists") + end + + data = { + 'CacheSecurityGroupName' => name, + 'Description' => description, + 'EC2SecurityGroups' => [], + 'OwnerId' => '0123456789' + } + self.data[:security_groups][name] = data + + Excon::Response.new( + { + :body => { + 'ResponseMetadata'=>{ 'RequestId'=> Fog::AWS::Mock.request_id }, + 'CacheSecurityGroup' => data + } + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/create_cache_subnet_group.rb b/lib/fog/aws/requests/elasticache/create_cache_subnet_group.rb new file mode 100644 index 000000000..3554e1a3a --- /dev/null +++ b/lib/fog/aws/requests/elasticache/create_cache_subnet_group.rb @@ -0,0 +1,60 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/create_cache_subnet_group' + + # Creates a cache subnet group + # http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/API_CreateCacheSubnetGroup.html + # + # ==== Parameters + # * CacheSubnetGroupName <~String> - A name for the cache subnet group. This value is stored as a lowercase string. Must contain no more than 255 alphanumeric characters or hyphens. + # * SubnetIds <~Array> - The VPC subnet IDs for the cache subnet group. + # * CacheSubnetGroupDescription <~String> - A description for the cache subnet group. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_cache_subnet_group(name, subnet_ids, description = name) + params = { + 'Action' => 'CreateCacheSubnetGroup', + 'CacheSubnetGroupName' => name, + 'CacheSubnetGroupDescription' => description, + :parser => Fog::Parsers::AWS::Elasticache::CreateCacheSubnetGroup.new + } + params.merge!(Fog::AWS.indexed_param("SubnetIds.member", Array(subnet_ids))) + request(params) + end + end + + class Mock + def create_cache_subnet_group(name, subnet_ids, description = name) + response = Excon::Response.new + if self.data[:subnet_groups] && self.data[:subnet_groups][name] + raise Fog::AWS::Elasticache::IdentifierTaken.new("CacheSubnetGroupAlreadyExists => The subnet group '#{name}' already exists") + end + + collection = Fog::Compute[:aws] + collection.region = @region + subnets = collection.subnets + + subnets = subnet_ids.map { |snid| subnets.get(snid) } + vpc_id = subnets.first.vpc_id + + data = { + 'CacheSubnetGroupName' => name, + 'CacheSubnetGroupDescription' => description, + 'SubnetGroupStatus' => 'Complete', + 'Subnets' => subnet_ids, + 'VpcId' => vpc_id + } + self.data[:subnet_groups][name] = data + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + 'CreateCacheSubnetGroupResult' => { 'CacheSubnetGroup' => data } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/delete_cache_cluster.rb b/lib/fog/aws/requests/elasticache/delete_cache_cluster.rb new file mode 100644 index 000000000..4aab675c3 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/delete_cache_cluster.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_cache_clusters' + + # Deletes a Cache Cluster + # + # === Parameter (required): + # * id <~String> - The ID of the cache cluster to delete + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def delete_cache_cluster(cluster_id) + request( + 'Action' => 'DeleteCacheCluster', + 'CacheClusterId' => cluster_id, + :parser => Fog::Parsers::AWS::Elasticache::DescribeCacheClusters.new + ) + end + end + + class Mock + def delete_cache_cluster(cluster_id) + response = Excon::Response.new + cluster = self.data[:clusters][cluster_id] + cluster['CacheClusterStatus'] = 'deleting' + response.body = { + 'CacheClusters' => self.data[:clusters].values, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + self.data[:clusters].delete(cluster_id) + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/delete_cache_parameter_group.rb b/lib/fog/aws/requests/elasticache/delete_cache_parameter_group.rb new file mode 100644 index 000000000..314d49279 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/delete_cache_parameter_group.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/base' + + # deletes a cache parameter group + # + # === Parameters + # * name <~String> - The name for the Cache Parameter Group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def delete_cache_parameter_group(name) + request({ + 'Action' => 'DeleteCacheParameterGroup', + 'CacheParameterGroupName' => name, + :parser => Fog::Parsers::AWS::Elasticache::Base.new + }) + end + end + + class Mock + def delete_cache_parameter_group(name) + response = Excon::Response.new + + if self.data[:parameter_groups].delete(name) + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + } + response + else + raise Fog::AWS::Elasticache::NotFound.new("CacheParameterGroup not found: #{name}") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/delete_cache_security_group.rb b/lib/fog/aws/requests/elasticache/delete_cache_security_group.rb new file mode 100644 index 000000000..93cb7b3a2 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/delete_cache_security_group.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/base' + + # deletes a cache security group + # + # === Parameters + # * name <~String> - The name for the Cache Security Group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def delete_cache_security_group(name) + request({ + 'Action' => 'DeleteCacheSecurityGroup', + 'CacheSecurityGroupName' => name, + :parser => Fog::Parsers::AWS::Elasticache::Base.new + }) + end + end + + class Mock + def delete_cache_security_group(name) + if self.data[:security_groups].delete(name) + Excon::Response.new( + { + :status => 200, + :body => { 'ResponseMetadata'=>{ 'RequestId'=> Fog::AWS::Mock.request_id } } + } + ) + else + raise Fog::AWS::RDS::NotFound.new("DBSecurityGroupNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/delete_cache_subnet_group.rb b/lib/fog/aws/requests/elasticache/delete_cache_subnet_group.rb new file mode 100644 index 000000000..b81833786 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/delete_cache_subnet_group.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/base' + + # deletes a cache subnet group + # + # === Parameters + # * name <~String> - The name for the Cache Subnet Group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def delete_cache_subnet_group(name) + request({ + 'Action' => 'DeleteCacheSubnetGroup', + 'CacheSubnetGroupName' => name, + :parser => Fog::Parsers::AWS::Elasticache::Base.new + }) + end + end + + class Mock + def delete_cache_subnet_group(name) + if self.data[:subnet_groups].delete(name) + Excon::Response.new( + { + :status => 200, + :body => { 'ResponseMetadata'=>{ 'RequestId'=> Fog::AWS::Mock.request_id } } + } + ) + else + raise Fog::AWS::Elasticache::NotFound.new("CacheSubnetGroupNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_cache_clusters.rb b/lib/fog/aws/requests/elasticache/describe_cache_clusters.rb new file mode 100644 index 000000000..8832b3d8b --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_cache_clusters.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_cache_clusters' + + # Returns a list of Cache Cluster descriptions + # + # === Parameters (optional) + # * id - The ID of an existing cache cluster + # * options <~Hash> (optional): + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + # * :show_node_info <~Boolean> - whether to show node info + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def describe_cache_clusters(id = nil, options = {}) + request({ + 'Action' => 'DescribeCacheClusters', + 'CacheClusterId' => id, + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + 'ShowCacheNodeInfo' => options[:show_node_info], + :parser => Fog::Parsers::AWS::Elasticache::DescribeCacheClusters.new + }) + end + end + + class Mock + def describe_cache_clusters(id = nil, options = {}) + response = Excon::Response.new + all_clusters = self.data[:clusters].values.map do |cluster| + cluster.merge!(options[:show_node_info] ? { + 'CacheClusterCreateTime' => DateTime.now - 60, + 'PreferredAvailabilityZone' => 'us-east-1a' + } : {}) + end + if (id != nil) && (all_clusters.empty?) + raise Fog::AWS::Elasticache::NotFound + end + response.body = { + 'CacheClusters' => all_clusters, + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_cache_parameter_groups.rb b/lib/fog/aws/requests/elasticache/describe_cache_parameter_groups.rb new file mode 100644 index 000000000..fff534899 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_cache_parameter_groups.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_parameter_groups' + + # Returns a list of CacheParameterGroup descriptions + # + # === Parameters (optional) + # * name <~String> - The name of an existing cache parameter group + # * options <~Hash> (optional): + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + def describe_cache_parameter_groups(name = nil, options = {}) + request({ + 'Action' => 'DescribeCacheParameterGroups', + 'CacheParameterGroupName' => name, + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + :parser => Fog::Parsers::AWS::Elasticache::DescribeParameterGroups.new + }.merge(options)) + end + end + + class Mock + def describe_cache_parameter_groups(name = nil, options = {}) + response = Excon::Response.new + parameter_set = [] + if name + if server = self.data[:parameter_groups][name] + parameter_set << server + else + raise Fog::AWS::Elasticache::NotFound.new("CacheParameterGroup #{name} not found") + end + else + parameter_set = self.data[:parameter_groups].values + end + + response.status = 200 + + response.body = { "CacheParameterGroups" => parameter_set } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_cache_parameters.rb b/lib/fog/aws/requests/elasticache/describe_cache_parameters.rb new file mode 100644 index 000000000..a49813df0 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_cache_parameters.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_cache_parameters' + + # Returns a list of CacheParameterGroup descriptions + # + # === Parameters (optional) + # * name <~String> - The name of an existing cache parameter group + # * options <~Hash> (optional): + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + # * :source <~String> - the parameter types to return. + def describe_cache_parameters(name = nil, options = {}) + request({ + 'Action' => 'DescribeCacheParameters', + 'CacheParameterGroupName' => name, + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + 'Source' => options[:source], + :parser => Fog::Parsers::AWS::Elasticache::DescribeCacheParameters.new + }) + end + end + + class Mock + def describe_cache_parameters(name = nil, options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_cache_security_groups.rb b/lib/fog/aws/requests/elasticache/describe_cache_security_groups.rb new file mode 100644 index 000000000..a52ae7805 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_cache_security_groups.rb @@ -0,0 +1,64 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_security_groups' + + # Returns a list of CacheSecurityGroup descriptions + # + # === Parameters (optional) + # * name <~String> - The name of an existing cache security group + # * options <~Hash> (optional): + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + def describe_cache_security_groups(name = nil, options = {}) + request({ + 'Action' => 'DescribeCacheSecurityGroups', + 'CacheSecurityGroupName' => name, + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + :parser => Fog::Parsers::AWS::Elasticache::DescribeSecurityGroups.new + }.merge(options)) + end + end + + class Mock + def describe_cache_security_groups(name = nil, opts={}) + if name + sec_group_set = [self.data[:security_groups][name]].compact + raise Fog::AWS::Elasticache::NotFound.new("Security Group #{name} not found") if sec_group_set.empty? + else + sec_group_set = self.data[:security_groups].values + end + + # TODO: refactor to not delete items that we're iterating over. Causes + # model tests to fail (currently pending) + sec_group_set.each do |sec_group| + # TODO: refactor to not delete items that we're iterating over. Causes + # model tests to fail (currently pending) + sec_group["EC2SecurityGroups"].each do |ec2_secg| + if ec2_secg["Status"] == "authorizing" || ec2_secg["Status"] == "revoking" + ec2_secg[:tmp] ||= Time.now + Fog::Mock.delay * 2 + if ec2_secg[:tmp] <= Time.now + ec2_secg["Status"] = "authorized" if ec2_secg["Status"] == "authorizing" + ec2_secg.delete(:tmp) + sec_group["EC2SecurityGroups"].delete(ec2_secg) if ec2_secg["Status"] == "revoking" + end + end + end + end + + Excon::Response.new( + { + :status => 200, + :body => { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CacheSecurityGroups" => sec_group_set + } + } + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_cache_subnet_groups.rb b/lib/fog/aws/requests/elasticache/describe_cache_subnet_groups.rb new file mode 100644 index 000000000..cf75454db --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_cache_subnet_groups.rb @@ -0,0 +1,59 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_cache_subnet_groups' + + # This API returns a list of CacheSubnetGroup descriptions. If a CacheSubnetGroupName is specified, the list will contain only + # the descriptions of the specified CacheSubnetGroup + # http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/API_DescribeCacheSubnetGroups.html + # ==== Parameters + # * CacheSubnetGroupName <~String> - The name of a specific database subnet group to return details for. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_cache_subnet_groups(name = nil, opts = {}) + params = {} + if opts[:marker] + params['Marker'] = opts[:marker] + end + if name + params['CacheSubnetGroupName'] = name + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeCacheSubnetGroups', + :parser => Fog::Parsers::AWS::Elasticache::DescribeCacheSubnetGroups.new + }.merge(params)) + end + end + + class Mock + def describe_cache_subnet_groups(name = nil, opts = {}) + response = Excon::Response.new + + subnet_group_set = [] + if name + if subnet_group = self.data[:subnet_groups][name] + subnet_group_set << subnet_group + else + raise Fog::AWS::Elasticache::NotFound.new("Subnet Group #{name} not found") + end + else + subnet_group_set = self.data[:subnet_groups].values + end + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeCacheSubnetGroupsResult" => { "CacheSubnetGroups" => subnet_group_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_engine_default_parameters.rb b/lib/fog/aws/requests/elasticache/describe_engine_default_parameters.rb new file mode 100644 index 000000000..bea25614b --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_engine_default_parameters.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_engine_default_parameters' + + # Returns the default engine and system parameter information + # for the specified cache engine. + # + # === Parameters (optional) + # * options <~Hash>: + # * :engine <~String> - the engine whose parameters are requested + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + def describe_engine_default_parameters(options = {}) + request({ + 'Action' => 'DescribeEngineDefaultParameters', + 'CacheParameterGroupFamily' => options[:engine] || 'memcached1.4', + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + :parser => Fog::Parsers::AWS::Elasticache::DescribeEngineDefaultParameters.new + }) + end + end + + class Mock + def describe_engine_defalut_parameters(options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_events.rb b/lib/fog/aws/requests/elasticache/describe_events.rb new file mode 100644 index 000000000..28d1f91c5 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_events.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/event_list' + + # Returns a list of service events + # + # For more information see: + # http://docs.amazonwebservices.com/AmazonElastiCache/latest/APIReference/API_DescribeEvents.html + # + # === Parameters (optional) + # * options <~Hash> (optional): + # * :start_time <~DateTime> - starting time for event records + # * :end_time <~DateTime> - ending time for event records + # * :duration <~Integer> - time span for event records + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + # * :source_identifier <~String> - identifier of the event source + # * :source_type <~String> - event type, one of: + # (cache-cluster | cache-parameter-group | cache-security-group) + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def describe_events(options = {}) + request( + 'Action' => 'DescribeEvents', + 'StartTime' => options[:start_time], + 'EndTime' => options[:end_time], + 'Duration' => options[:duration], + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + 'SourceIdentifier' => options[:source_identifier], + 'SourceType' => options[:source_type], + :parser => Fog::Parsers::AWS::Elasticache::EventListParser.new + ) + end + end + + class Mock + def describe_events + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_reserved_cache_nodes.rb b/lib/fog/aws/requests/elasticache/describe_reserved_cache_nodes.rb new file mode 100644 index 000000000..ae37ba77f --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_reserved_cache_nodes.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/describe_reserved_cache_nodes' + + # Describe all or specified reserved Elasticache nodes + # http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/API_DescribeReservedCacheNodes.html + # ==== Parameters + # * ReservedCacheNodeId <~String> - ID of node to retrieve information for. If absent, information for all nodes is returned. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_reserved_cache_nodes(identifier=nil, opts={}) + params = {} + params['ReservedCacheNodeId'] = identifier if identifier + if opts[:marker] + params['Marker'] = opts[:marker] + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeReservedCacheNodes', + :parser => Fog::Parsers::AWS::Elasticache::DescribeReservedCacheNodes.new + }.merge(params)) + end + end + + class Mock + def describe_db_reserved_instances(identifier=nil, opts={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/modify_cache_cluster.rb b/lib/fog/aws/requests/elasticache/modify_cache_cluster.rb new file mode 100644 index 000000000..bd661b794 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/modify_cache_cluster.rb @@ -0,0 +1,99 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_cache_cluster' + + # Modifies an existing cache cluster + # Returns a cache cluster description + # + # === Required Parameters + # * id <~String> - The ID of the existing cluster to be modified + # === Optional Parameters + # * options <~Hash> - All optional parameters should be set in this Hash: + # * :apply_immediately <~TrueFalseClass> - whether to apply changes now + # * :auto_minor_version_upgrade <~TrueFalseClass> + # * :num_nodes <~Integer> - The number of nodes in the Cluster + # * :nodes_to_remove <~Array> - Array of node IDs to delete + # * :security_group_names <~Array> - Array of Elasticache::SecurityGroup names + # * :parameter_group_name <~String> - Name of the Cluster's ParameterGroup + # * :engine_version <~String> - The Cluster's caching software version + # * :notification_topic_arn <~String> - Amazon SNS Resource Name + # * :notification_topic_status <~String> - Amazon SNS Topic status + # * :preferred_maintenance_window <~String> + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def modify_cache_cluster(id, options = {}) + # Construct Cache Security Group parameters in the format: + # CacheSecurityGroupNames.member.N => "security_group_name" + group_names = options[:security_group_names] || [] + sec_group_params = group_names.reduce({}) do |group_hash, name| + index = group_names.index(name) + 1 + group_hash["CacheSecurityGroupNames.member.#{index}"] = name + group_hash + end + # Construct CacheNodeIdsToRemove parameters in the format: + # CacheNodeIdsToRemove.member.N => "node_id" + node_ids = options[:nodes_to_remove] || [] + node_id_params = node_ids.reduce({}) do |node_hash, node_id| + index = node_ids.index(node_id) + 1 + node_hash["CacheNodeIdsToRemove.member.#{index}"] = node_id + node_hash + end + # Merge the Cache Security Group parameters with the normal options + request(node_id_params.merge(sec_group_params.merge( + 'Action' => 'ModifyCacheCluster', + 'CacheClusterId' => id.strip, + 'ApplyImmediately' => options[:apply_immediately], + 'NumCacheNodes' => options[:num_nodes], + 'AutoMinorVersionUpgrade' => options[:auto_minor_version_upgrade], + 'CacheParameterGroupName' => options[:parameter_group_name], + 'EngineVersion' => options[:engine_version], + 'NotificationTopicArn' => options[:notification_topic_arn], + 'NotificationTopicStatus' => options[:notification_topic_status], + 'PreferredMaintenanceWindow' => options[:preferred_maintenance_window], + :parser => Fog::Parsers::AWS::Elasticache::SingleCacheCluster.new + ))) + end + end + + class Mock + def modify_cache_cluster(id, options = {}) + response = Excon::Response.new + cluster = self.data[:clusters][id] + pending_values = Hash.new + # For any given option, update the cluster's corresponding value + { :auto_minor_version_upgrade => 'AutoMinorVersionUpgrade', + :preferred_maintenance_window => 'PreferredMaintenanceWindow', + :engine_version => 'EngineVersion', + :num_nodes => 'NumCacheNodes', + }.each do |option, cluster_key| + if options[option] != nil + cluster[cluster_key] = options[option].to_s + pending_values[cluster_key] = options[option] + end + end + cache['CacheParameterGroup'] = { + 'CacheParameterGroupName' => options[:parameter_group_name] + } if options[:parameter_group_name] + if options[:num_nodes] || options[:engine_version] + cluster['CacheNodes'] = + create_cache_nodes(cluster['CacheClusterId'], options[:num_nodes]) + cluster['NumCacheNodes'] = cluster['CacheNodes'].size + end + if options[:nodes_to_remove] + pending_values['CacheNodeId'] = options[:nodes_to_remove].join(',') + end + response.body = { + 'CacheCluster' => cluster.merge({ + 'PendingModifiedValues' => pending_values + }), + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/modify_cache_parameter_group.rb b/lib/fog/aws/requests/elasticache/modify_cache_parameter_group.rb new file mode 100644 index 000000000..7585e4675 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/modify_cache_parameter_group.rb @@ -0,0 +1,43 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/modify_parameter_group' + + # Modifies an existing cache parameter group + # Returns a the name of the modified parameter group + # + # === Required Parameters + # * id <~String> - The ID of the parameter group to be modified + # * new_parameters <~Hash> - The parameters to modify, and their values + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def modify_cache_parameter_group(id, new_parameters) + # Construct Parameter Modifications in the format: + # ParameterNameValues.member.N.ParameterName => "param_name" + # ParameterNameValues.member.N.ParameterValue => "param_value" + n = 0 # n is the parameter index + parameter_changes = new_parameters.reduce({}) do |new_args,pair| + n += 1 + new_args["ParameterNameValues.member.#{n}.ParameterName"] = pair[0] + new_args["ParameterNameValues.member.#{n}.ParameterValue"] = pair[1] + new_args + end + # Merge the Cache Security Group parameters with the normal options + request(parameter_changes.merge( + 'Action' => 'ModifyCacheParameterGroup', + 'CacheParameterGroupName' => id, + :parser => Fog::Parsers::AWS::Elasticache::ModifyParameterGroup.new + )) + end + end + + class Mock + def modify_cache_parameter_group(id, new_parameters) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/reboot_cache_cluster.rb b/lib/fog/aws/requests/elasticache/reboot_cache_cluster.rb new file mode 100644 index 000000000..0ea8d8220 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/reboot_cache_cluster.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_cache_cluster' + + # Reboots some or all of an existing cache cluster's nodes + # Returns a cache cluster description + # + # === Required Parameters + # * id <~String> - The ID of the existing cluster to be rebooted + # === Optional Parameters + # * nodes_to_reboot <~Array> - Array of node IDs to reboot + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def reboot_cache_cluster(id, nodes_to_reboot) + # Construct CacheNodeIdsToReboot parameters in the format: + # CacheNodeIdsToReboot.member.N => "node_id" + node_ids = nodes_to_reboot || [] + node_id_params = node_ids.reduce({}) do |node_hash, node_id| + index = node_ids.index(node_id) + 1 + node_hash["CacheNodeIdsToReboot.member.#{index}"] = node_id + node_hash + end + # Merge the CacheNodeIdsToReboot parameters with the normal options + request(node_id_params.merge( + 'Action' => 'RebootCacheCluster', + 'CacheClusterId' => id, + :parser => Fog::Parsers::AWS::Elasticache::SingleCacheCluster.new + )) + end + end + + class Mock + def reboot_cache_cluster(id, nodes_to_reboot) + response = Excon::Response.new + response.body = { + 'CacheCluster' => self.data[:clusters][id].merge({ + 'CacheClusterStatus' => 'rebooting cache cluster nodes' + }), + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/reset_cache_parameter_group.rb b/lib/fog/aws/requests/elasticache/reset_cache_parameter_group.rb new file mode 100644 index 000000000..8dc9d8e5e --- /dev/null +++ b/lib/fog/aws/requests/elasticache/reset_cache_parameter_group.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/reset_parameter_group' + + # Resets an existing cache parameter group + # Returns a the name of the modified parameter group + # + # === Required Parameters + # * id <~String> - The ID of the parameter group to be modified + # === Optional Parameters + # * parameter_names <~Array> - The parameters to reset + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def reset_cache_parameter_group(id, parameter_names = []) + # Construct Parameter resets in the format: + # ParameterNameValues.member.N => "param_name" + parameter_changes = parameter_names.reduce({}) do |new_args, param| + index = parameter_names.index(param) + 1 + new_args["ParameterNameValues.member.#{index}"] = param + new_args + end + if parameter_changes.empty? + parameter_changes = {'ResetAllParameters' => 'true'} + end + # Merge the Cache Security Group parameters with the normal options + request(parameter_changes.merge( + 'Action' => 'ResetCacheParameterGroup', + 'CacheParameterGroupName' => id, + :parser => Fog::Parsers::AWS::Elasticache::ResetParameterGroup.new + )) + end + end + + class Mock + def reset_cache_parameter_group(id, parameter_names) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/revoke_cache_security_group_ingress.rb b/lib/fog/aws/requests/elasticache/revoke_cache_security_group_ingress.rb new file mode 100644 index 000000000..f740eb96c --- /dev/null +++ b/lib/fog/aws/requests/elasticache/revoke_cache_security_group_ingress.rb @@ -0,0 +1,35 @@ + +module Fog + module AWS + class Elasticache + class Real + require 'fog/aws/parsers/elasticache/single_security_group' + + # Revoke ingress to a CacheSecurityGroup using EC2 Security Groups + # + # === Parameters + # * name <~String> - The name of the cache security group + # * ec2_name <~String> - The name of the EC2 security group to revoke + # * ec2_owner_id <~String> - The Aws Account Number of the EC2 security group + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def revoke_cache_security_group_ingress(name, ec2_name, ec2_owner_id) + request({ + 'Action' => 'RevokeCacheSecurityGroupIngress', + 'CacheSecurityGroupName' => name, + 'EC2SecurityGroupName' => ec2_name, + 'EC2SecurityGroupOwnerId' => ec2_owner_id, + :parser => Fog::Parsers::AWS::Elasticache::SingleSecurityGroup.new + }) + end + end + + class Mock + def revoke_cache_security_group_ingress + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/add_tags.rb b/lib/fog/aws/requests/elb/add_tags.rb new file mode 100644 index 000000000..cb06d924b --- /dev/null +++ b/lib/fog/aws/requests/elb/add_tags.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class ELB + class Real + + # adds tags to a load balancer instance + # http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_AddTags.html + # ==== Parameters + # * elb_id <~String> - name of the ELB instance to be tagged + # * tags <~Hash> A Hash of (String) key-value pairs + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def add_tags(elb_id, tags) + keys = tags.keys.sort + values = keys.map {|key| tags[key]} + request({ + 'Action' => 'AddTags', + 'LoadBalancerNames.member.1' => elb_id, + :parser => Fog::Parsers::AWS::ELB::Empty.new, + }.merge(Fog::AWS.indexed_param('Tags.member.%d.Key', keys)). + merge(Fog::AWS.indexed_param('Tags.member.%d.Value', values))) + end + + end + + class Mock + + def add_tags(elb_id, tags) + response = Excon::Response.new + if server = self.data[:load_balancers][elb_id] + self.data[:tags][elb_id].merge! tags + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id } + } + response + else + raise Fog::AWS::ELB::NotFound.new("Elastic load balancer #{elb_id} not found") + end + end + + end + end + end +end diff --git a/lib/fog/aws/requests/elb/apply_security_groups_to_load_balancer.rb b/lib/fog/aws/requests/elb/apply_security_groups_to_load_balancer.rb new file mode 100644 index 000000000..b01a2aed1 --- /dev/null +++ b/lib/fog/aws/requests/elb/apply_security_groups_to_load_balancer.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/apply_security_groups_to_load_balancer' + + # Sets the security groups for an ELB in VPC + # + # ==== Parameters + # * security_group_ids<~Array> - List of security group ids to enable on ELB + # * lb_name<~String> - Load balancer to disable availability zones on + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'ApplySecurityGroupsToLoadBalancer'<~Hash>: + # * 'SecurityGroups'<~Array> - array of strings describing the security group ids currently enabled + def apply_security_groups_to_load_balancer(security_group_ids, lb_name) + params = Fog::AWS.indexed_param('SecurityGroups.member', [*security_group_ids]) + request({ + 'Action' => 'ApplySecurityGroupsToLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::ApplySecurityGroupsToLoadBalancer.new + }.merge!(params)) + end + + alias_method :apply_security_groups, :apply_security_groups_to_load_balancer + end + + class Mock + def apply_security_groups_to_load_balancer(security_group_ids, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + response = Excon::Response.new + response.status = 200 + + load_balancer['SecurityGroups'] << security_group_ids + load_balancer['SecurityGroups'].flatten!.uniq! + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DetachLoadBalancerFromSubnetsResult' => { + 'SecurityGroups' => load_balancer['SecurityGroups'] + } + } + + response + end + + alias_method :apply_security_groups, :apply_security_groups_to_load_balancer + end + end + end +end diff --git a/lib/fog/aws/requests/elb/attach_load_balancer_to_subnets.rb b/lib/fog/aws/requests/elb/attach_load_balancer_to_subnets.rb new file mode 100644 index 000000000..ad2de9717 --- /dev/null +++ b/lib/fog/aws/requests/elb/attach_load_balancer_to_subnets.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/attach_load_balancer_to_subnets' + + # Enable a subnet for an existing ELB + # + # ==== Parameters + # * subnet_ids<~Array> - List of subnet ids to enable on ELB + # * lb_name<~String> - Load balancer to enable availability zones on + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'AttachLoadBalancerToSubnetsResult'<~Hash>: + # * 'Subnets'<~Array> - array of strings describing the subnet ids currently enabled + def attach_load_balancer_to_subnets(subnet_ids, lb_name) + params = Fog::AWS.indexed_param('Subnets.member', [*subnet_ids]) + request({ + 'Action' => 'AttachLoadBalancerToSubnets', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::AttachLoadBalancerToSubnets.new + }.merge!(params)) + end + + alias_method :enable_subnets, :attach_load_balancer_to_subnets + end + + class Mock + def attach_load_balancer_to_subnets(subnet_ids, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + response = Excon::Response.new + response.status = 200 + + load_balancer['Subnets'] << subnet_ids + load_balancer['Subnets'].flatten!.uniq! + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'AttachLoadBalancerToSubnetsResult' => { + 'Subnets' => load_balancer['Subnets'] + } + } + + response + end + + alias_method :enable_subnets, :attach_load_balancer_to_subnets + end + end + end +end diff --git a/lib/fog/aws/requests/elb/configure_health_check.rb b/lib/fog/aws/requests/elb/configure_health_check.rb new file mode 100644 index 000000000..6ad8d33c8 --- /dev/null +++ b/lib/fog/aws/requests/elb/configure_health_check.rb @@ -0,0 +1,63 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/configure_health_check' + + # Enables the client to define an application healthcheck for the instances. + # See http://docs.amazonwebservices.com/ElasticLoadBalancing/latest/APIReference/index.html?API_ConfigureHealthCheck.html + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * health_check<~Hash> - A hash of parameters describing the health check + # * 'HealthyThreshold'<~Integer> - Specifies the number of consecutive + # health probe successes required before moving the instance to the Healthy state. + # * 'Interval'<~Integer> - Specifies the approximate interval, in seconds, + # between health checks of an individual instance. + # * 'Target'<~String> - Specifies the instance being checked. + # The protocol is either TCP or HTTP. The range of valid ports is one (1) through 65535. + # * 'Timeout'<~Integer> - Specifies the amount of time, in seconds, + # during which no response means a failed health probe. + # * 'UnhealthyThreshold'<~Integer> - Specifies the number of consecutive + # health probe failures required before moving the instance to the Unhealthy state. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def configure_health_check(lb_name, health_check) + params = {'LoadBalancerName' => lb_name} + health_check.each {|key, value| params["HealthCheck.#{key}"] = value } + + request({ + 'Action' => 'ConfigureHealthCheck', + :parser => Fog::Parsers::AWS::ELB::ConfigureHealthCheck.new + }.merge!(params)) + end + end + + class Mock + def configure_health_check(lb_name, health_check) + if load_balancer = self.data[:load_balancers][lb_name] + response = Excon::Response.new + response.status = 200 + + load_balancer['HealthCheck'] = health_check + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'ConfigureHealthCheckResult' => { + 'HealthCheck' => load_balancer['HealthCheck'] + } + } + + response + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/create_app_cookie_stickiness_policy.rb b/lib/fog/aws/requests/elb/create_app_cookie_stickiness_policy.rb new file mode 100644 index 000000000..fe203de4a --- /dev/null +++ b/lib/fog/aws/requests/elb/create_app_cookie_stickiness_policy.rb @@ -0,0 +1,52 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Create an app cookie stickiness policy + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * policy_name<~String> - The name of the policy being created. + # The name must be unique within the set of policies for this Load Balancer. + # * cookie_name<~String> - Name of the application cookie used for stickiness. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def create_app_cookie_stickiness_policy(lb_name, policy_name, cookie_name) + params = {'CookieName' => cookie_name, 'PolicyName' => policy_name} + + request({ + 'Action' => 'CreateAppCookieStickinessPolicy', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def create_app_cookie_stickiness_policy(lb_name, policy_name, cookie_name) + if load_balancer = self.data[:load_balancers][lb_name] + response = Excon::Response.new + response.status = 200 + + create_load_balancer_policy(lb_name, policy_name, 'AppCookieStickinessPolicyType', {'CookieName' => cookie_name}) + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/create_lb_cookie_stickiness_policy.rb b/lib/fog/aws/requests/elb/create_lb_cookie_stickiness_policy.rb new file mode 100644 index 000000000..985ef5759 --- /dev/null +++ b/lib/fog/aws/requests/elb/create_lb_cookie_stickiness_policy.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Create a Load Balancer Cookie Stickiness Policy + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * policy_name<~String> - The name of the policy being created. The name + # must be unique within the set of policies for this Load Balancer. + # * cookie_expiration_period<~Integer> - The time period in seconds after + # which the cookie should be considered stale. Not specifying this + # parameter indicates that the sticky session will last for the duration of the browser session. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def create_lb_cookie_stickiness_policy(lb_name, policy_name, cookie_expiration_period=nil) + params = {'PolicyName' => policy_name, 'CookieExpirationPeriod' => cookie_expiration_period} + + request({ + 'Action' => 'CreateLBCookieStickinessPolicy', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def create_lb_cookie_stickiness_policy(lb_name, policy_name, cookie_expiration_period=nil) + if load_balancer = self.data[:load_balancers][lb_name] + response = Excon::Response.new + response.status = 200 + + create_load_balancer_policy(lb_name, policy_name, 'LBCookieStickinessPolicyType', {'CookieExpirationPeriod' => cookie_expiration_period}) + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/create_load_balancer.rb b/lib/fog/aws/requests/elb/create_load_balancer.rb new file mode 100644 index 000000000..69d0199fb --- /dev/null +++ b/lib/fog/aws/requests/elb/create_load_balancer.rb @@ -0,0 +1,206 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/create_load_balancer' + + # Create a new Elastic Load Balancer + # + # ==== Parameters + # * availability_zones<~Array> - List of availability zones for the ELB + # * lb_name<~String> - Name for the new ELB -- must be unique + # * listeners<~Array> - Array of Hashes describing ELB listeners to assign to the ELB + # * 'Protocol'<~String> - Protocol to use. Either HTTP, HTTPS, TCP or SSL. + # * 'LoadBalancerPort'<~Integer> - The port that the ELB will listen to for outside traffic + # * 'InstancePort'<~Integer> - The port on the instance that the ELB will forward traffic to + # * 'InstanceProtocol'<~String> - Protocol for sending traffic to an instance. Either HTTP, HTTPS, TCP or SSL. + # * 'SSLCertificateId'<~String> - ARN of the server certificate + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'CreateLoadBalancerResult'<~Hash>: + # * 'DNSName'<~String> - DNS name for the newly created ELB + def create_load_balancer(availability_zones, lb_name, listeners, options = {}) + params = Fog::AWS.indexed_param('AvailabilityZones.member', [*availability_zones]) + params.merge!(Fog::AWS.indexed_param('Subnets.member.%d', options[:subnet_ids])) + params.merge!(Fog::AWS.serialize_keys('Scheme', options[:scheme])) + params.merge!(Fog::AWS.indexed_param('SecurityGroups.member.%d', options[:security_groups])) + + listener_protocol = [] + listener_lb_port = [] + listener_instance_port = [] + listener_instance_protocol = [] + listener_ssl_certificate_id = [] + listeners.each do |listener| + listener_protocol.push(listener['Protocol']) + listener_lb_port.push(listener['LoadBalancerPort']) + listener_instance_port.push(listener['InstancePort']) + listener_instance_protocol.push(listener['InstanceProtocol']) + listener_ssl_certificate_id.push(listener['SSLCertificateId']) + end + + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.Protocol', listener_protocol)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.LoadBalancerPort', listener_lb_port)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.InstancePort', listener_instance_port)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.InstanceProtocol', listener_instance_protocol)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.SSLCertificateId', listener_ssl_certificate_id)) + + request({ + 'Action' => 'CreateLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::CreateLoadBalancer.new + }.merge!(params)) + end + end + + class Mock + def create_load_balancer(availability_zones, lb_name, listeners = [], options = {}) + response = Excon::Response.new + response.status = 200 + + raise Fog::AWS::ELB::IdentifierTaken if self.data[:load_balancers].key? lb_name + + certificate_ids = Fog::AWS::IAM::Mock.data[@aws_access_key_id][:server_certificates].map {|n, c| c['Arn'] } + + listeners = [*listeners].map do |listener| + if listener['SSLCertificateId'] and !certificate_ids.include? listener['SSLCertificateId'] + raise Fog::AWS::IAM::NotFound.new('CertificateNotFound') + end + {'Listener' => listener, 'PolicyNames' => []} + end + + dns_name = Fog::AWS::ELB::Mock.dns_name(lb_name, @region) + + availability_zones = [*availability_zones].compact + region = availability_zones.empty? ? "us-east-1" : availability_zones.first.gsub(/[a-z]$/, '') + supported_platforms = Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:account_attributes].find { |h| h["attributeName"] == "supported-platforms" }["values"] + subnet_ids = options[:subnet_ids] || [] + subnets = Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:subnets].select {|e| subnet_ids.include?(e["subnetId"]) } + + # http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/default-vpc.html + elb_location = if supported_platforms.include?("EC2") + if subnet_ids.empty? + 'EC2-Classic' + else + 'EC2-VPC' + end + else + if subnet_ids.empty? + 'EC2-VPC-Default' + else + 'VPC' + end + end + + security_group = case elb_location + when 'EC2-Classic' + Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:security_groups]['amazon-elb-sg'] + when 'EC2-VPC-Default' + # find or create default vpc + compute = Fog::Compute::AWS::new(:aws_access_key_id => @aws_access_key_id, :aws_secret_access_key => @aws_secret_access_key) + unless vpc = compute.vpcs.all.first + vpc = compute.vpcs.create('cidr_block' => '10.0.0.0/24') + end + + default_sg = Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:security_groups].values.find { |sg| + sg['groupName'] =~ /^default_elb/ && + sg["vpcId"] == vpc.id + } + + unless default_sg + default_sg = { + 'groupDescription' => 'default_elb security group', + 'groupName' => "default_elb_#{Fog::Mock.random_hex(6)}", + 'groupId' => Fog::AWS::Mock.security_group_id, + 'ipPermissionsEgress' => [], + 'ipPermissions' => [], + 'ownerId' => self.data[:owner_id], + 'vpcId' => vpc.id + } + Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:security_groups]['default'] = default_sg + end + + default_sg + when 'EC2-VPC' + # find or create default vpc security group + vpc_id = subnets.first["vpcId"] + default_sg = Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:security_groups].values.find { |sg| + sg['groupName'] == 'default' && + sg["vpcId"] == vpc_id + } + + unless default_sg + default_sg = { + 'groupDescription' => 'default elb security group', + 'groupName' => 'default', + 'groupId' => Fog::AWS::Mock.security_group_id, + 'ipPermissionsEgress' => [], + 'ipPermissions' => [], + 'ownerId' => self.data[:owner_id], + 'vpcId' => vpc_id + } + Fog::Compute::AWS::Mock.data[region][@aws_access_key_id][:security_groups]['default'] = default_sg + end + + default_sg + end + self.data[:tags] ||= {} + self.data[:tags][lb_name] = {} + + self.data[:load_balancers][lb_name] = { + 'AvailabilityZones' => availability_zones, + 'BackendServerDescriptions' => [], + # Hack to facilitate not updating the local data structure + # (BackendServerDescriptions) until we do a subsequent + # describe as that is how Aws behaves. + 'BackendServerDescriptionsRemote' => [], + 'Subnets' => options[:subnet_ids] || [], + 'Scheme' => options[:scheme].nil? ? 'internet-facing' : options[:scheme], + 'SecurityGroups' => options[:security_groups].nil? ? [] : options[:security_groups], + 'CanonicalHostedZoneName' => '', + 'CanonicalHostedZoneNameID' => '', + 'CreatedTime' => Time.now, + 'DNSName' => dns_name, + 'HealthCheck' => { + 'HealthyThreshold' => 10, + 'Timeout' => 5, + 'UnhealthyThreshold' => 2, + 'Interval' => 30, + 'Target' => 'TCP:80' + }, + 'Instances' => [], + 'ListenerDescriptions' => listeners, + 'LoadBalancerAttributes' => { + 'ConnectionDraining' => {'Enabled' => false, 'Timeout' => 300}, + 'CrossZoneLoadBalancing' => {'Enabled' => false}, + 'ConnectionSettings' => {'IdleTimeout' => 60} + }, + 'LoadBalancerName' => lb_name, + 'Policies' => { + 'AppCookieStickinessPolicies' => [], + 'LBCookieStickinessPolicies' => [], + 'OtherPolicies' => [], + 'Proper' => [] + }, + 'SourceSecurityGroup' => { + 'GroupName' => security_group['groupName'], + 'OwnerAlias' => '' + } + } + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'CreateLoadBalancerResult' => { + 'DNSName' => dns_name + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/create_load_balancer_listeners.rb b/lib/fog/aws/requests/elb/create_load_balancer_listeners.rb new file mode 100644 index 000000000..9e28a7507 --- /dev/null +++ b/lib/fog/aws/requests/elb/create_load_balancer_listeners.rb @@ -0,0 +1,86 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Create Elastic Load Balancer Listeners + # + # ==== Parameters + # * lb_name<~String> - Name for the new ELB -- must be unique + # * listeners<~Array> - Array of Hashes describing ELB listeners to add to the ELB + # * 'Protocol'<~String> - Protocol to use. Either HTTP, HTTPS, TCP or SSL. + # * 'LoadBalancerPort'<~Integer> - The port that the ELB will listen to for outside traffic + # * 'InstancePort'<~Integer> - The port on the instance that the ELB will forward traffic to + # * 'InstanceProtocol'<~String> - Protocol for sending traffic to an instance. Either HTTP, HTTPS, TCP or SSL. + # * 'SSLCertificateId'<~String> - ARN of the server certificate + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def create_load_balancer_listeners(lb_name, listeners) + params = {} + + listener_protocol = [] + listener_lb_port = [] + listener_instance_port = [] + listener_instance_protocol = [] + listener_ssl_certificate_id = [] + listeners.each do |listener| + listener_protocol.push(listener['Protocol']) + listener_lb_port.push(listener['LoadBalancerPort']) + listener_instance_port.push(listener['InstancePort']) + listener_instance_protocol.push(listener['InstanceProtocol']) + listener_ssl_certificate_id.push(listener['SSLCertificateId']) + end + + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.Protocol', listener_protocol)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.LoadBalancerPort', listener_lb_port)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.InstancePort', listener_instance_port)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.InstanceProtocol', listener_instance_protocol)) + params.merge!(Fog::AWS.indexed_param('Listeners.member.%d.SSLCertificateId', listener_ssl_certificate_id)) + + request({ + 'Action' => 'CreateLoadBalancerListeners', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def create_load_balancer_listeners(lb_name, listeners) + if load_balancer = self.data[:load_balancers][lb_name] + response = Excon::Response.new + + certificate_ids = Fog::AWS::IAM::Mock.data[@aws_access_key_id][:server_certificates].map {|n, c| c['Arn'] } + + listeners.each do |listener| + if listener['SSLCertificateId'] and !certificate_ids.include? listener['SSLCertificateId'] + raise Fog::AWS::IAM::NotFound.new('CertificateNotFound') + end + + if (%w( HTTP HTTPS).include?(listener['Protocol']) && !%w( HTTP HTTPS ).include?(listener['InstanceProtocol'])) || + (%w( TCP SSL).include?(listener['Protocol']) && !%w( TCP SSL ).include?(listener['InstanceProtocol'])) + raise Fog::AWS::ELB::ValidationError + end if listener['Protocol'] && listener['InstanceProtocol'] + load_balancer['ListenerDescriptions'] << {'Listener' => listener, 'PolicyNames' => []} + end + + response.status = 200 + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/create_load_balancer_policy.rb b/lib/fog/aws/requests/elb/create_load_balancer_policy.rb new file mode 100644 index 000000000..580d08373 --- /dev/null +++ b/lib/fog/aws/requests/elb/create_load_balancer_policy.rb @@ -0,0 +1,80 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Create Elastic Load Balancer Policy + # + # ==== Parameters + # * lb_name<~String> - The name associated with the LoadBalancer for which the policy is being created. This name must be unique within the client Aws account. + # * attributes<~Hash> - A list of attributes associated with the policy being created. + # * 'AttributeName'<~String> - The name of the attribute associated with the policy. + # * 'AttributeValue'<~String> - The value of the attribute associated with the policy. + # * name<~String> - The name of the LoadBalancer policy being created. The name must be unique within the set of policies for this LoadBalancer. + # * type_name<~String> - The name of the base policy type being used to create this policy. To get the list of policy types, use the DescribeLoadBalancerPolicyTypes action. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def create_load_balancer_policy(lb_name, name, type_name, attributes = {}) + params = {} + + attribute_name = [] + attribute_value = [] + attributes.each do |name, value| + attribute_name.push(name) + attribute_value.push(value) + end + + params.merge!(Fog::AWS.indexed_param('PolicyAttributes.member.%d.AttributeName', attribute_name)) + params.merge!(Fog::AWS.indexed_param('PolicyAttributes.member.%d.AttributeValue', attribute_value)) + + request({ + 'Action' => 'CreateLoadBalancerPolicy', + 'LoadBalancerName' => lb_name, + 'PolicyName' => name, + 'PolicyTypeName' => type_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def create_load_balancer_policy(lb_name, name, type_name, attributes = {}) + if load_balancer = self.data[:load_balancers][lb_name] + raise Fog::AWS::ELB::DuplicatePolicyName, name if policy = load_balancer['Policies']['Proper'].find { |p| p['PolicyName'] == name } + raise Fog::AWS::ELB::PolicyTypeNotFound, type_name unless policy_type = self.data[:policy_types].find { |pt| pt['PolicyTypeName'] == type_name } + + response = Excon::Response.new + + attributes = attributes.map do |key, value| + if key == "CookieExpirationPeriod" && !value + value = 0 + end + {"AttributeName" => key, "AttributeValue" => value.to_s} + end + + load_balancer['Policies']['Proper'] << { + 'PolicyAttributeDescriptions' => attributes, + 'PolicyName' => name, + 'PolicyTypeName' => type_name + } + + response.status = 200 + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/delete_load_balancer.rb b/lib/fog/aws/requests/elb/delete_load_balancer.rb new file mode 100644 index 000000000..fec9187be --- /dev/null +++ b/lib/fog/aws/requests/elb/delete_load_balancer.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/delete_load_balancer' + + # Delete an existing Elastic Load Balancer + # + # Note that this API call, as defined by Amazon, is idempotent. + # That is, it will not return an error if you try to delete an + # ELB that does not exist. + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB to be deleted + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'DeleteLoadBalancerResponse'<~nil> + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def delete_load_balancer(lb_name) + request({ + 'Action' => 'DeleteLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DeleteLoadBalancer.new + }) + end + end + + class Mock + def delete_load_balancer(lb_name) + response = Excon::Response.new + response.status = 200 + + self.data[:load_balancers].delete(lb_name) + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DeleteLoadBalancerResult' => nil + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/delete_load_balancer_listeners.rb b/lib/fog/aws/requests/elb/delete_load_balancer_listeners.rb new file mode 100644 index 000000000..e8bc8f37a --- /dev/null +++ b/lib/fog/aws/requests/elb/delete_load_balancer_listeners.rb @@ -0,0 +1,48 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Delet Elastic Load Balancer Listeners + # + # ==== Parameters + # * lb_name<~String> - Name for the new ELB -- must be unique + # * load_balancer_ports<~Array> - Array of client port numbers of the LoadBalancerListeners to remove + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def delete_load_balancer_listeners(lb_name, load_balancer_ports) + params = Fog::AWS.indexed_param('LoadBalancerPorts.member.%d', load_balancer_ports) + + request({ + 'Action' => 'DeleteLoadBalancerListeners', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def delete_load_balancer_listeners(lb_name, load_balancer_ports) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + response = Excon::Response.new + response.status = 200 + + load_balancer['ListenerDescriptions'].delete_if { |listener| load_balancer_ports.include? listener['Listener']['LoadBalancerPort'] } + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/delete_load_balancer_policy.rb b/lib/fog/aws/requests/elb/delete_load_balancer_policy.rb new file mode 100644 index 000000000..7d5fd13c8 --- /dev/null +++ b/lib/fog/aws/requests/elb/delete_load_balancer_policy.rb @@ -0,0 +1,52 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Delete a Load Balancer Stickiness Policy + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * policy_name<~String> - The name of the policy to delete + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def delete_load_balancer_policy(lb_name, policy_name) + params = {'PolicyName' => policy_name} + + request({ + 'Action' => 'DeleteLoadBalancerPolicy', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def delete_load_balancer_policy(lb_name, policy_name) + if load_balancer = self.data[:load_balancers][lb_name] + response = Excon::Response.new + response.status = 200 + + load_balancer['Policies'].each do |name, policies| + policies.delete_if { |policy| policy['PolicyName'] == policy_name } + end + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/deregister_instances_from_load_balancer.rb b/lib/fog/aws/requests/elb/deregister_instances_from_load_balancer.rb new file mode 100644 index 000000000..b59ac48e5 --- /dev/null +++ b/lib/fog/aws/requests/elb/deregister_instances_from_load_balancer.rb @@ -0,0 +1,61 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/deregister_instances_from_load_balancer' + + # Deregister an instance from an existing ELB + # + # ==== Parameters + # * instance_ids<~Array> - List of instance IDs to remove from ELB + # * lb_name<~String> - Load balancer to remove instances from + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DeregisterInstancesFromLoadBalancerResult'<~Hash>: + # * 'Instances'<~Array> - array of hashes describing instances currently enabled + # * 'InstanceId'<~String> + def deregister_instances_from_load_balancer(instance_ids, lb_name) + params = Fog::AWS.indexed_param('Instances.member.%d.InstanceId', [*instance_ids]) + request({ + 'Action' => 'DeregisterInstancesFromLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DeregisterInstancesFromLoadBalancer.new + }.merge!(params)) + end + + alias_method :deregister_instances, :deregister_instances_from_load_balancer + end + + class Mock + def deregister_instances_from_load_balancer(instance_ids, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + instance_ids = [*instance_ids] + instance_ids.each do |instance| + raise Fog::AWS::ELB::InvalidInstance unless Fog::Compute::AWS::Mock.data[@region][@aws_access_key_id][:instances][instance] + end + + response = Excon::Response.new + response.status = 200 + + load_balancer['Instances'].delete_if { |i| instance_ids.include? i['InstanceId'] } + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DeregisterInstancesFromLoadBalancerResult' => { + 'Instances' => load_balancer['Instances'].dup + } + } + + response + end + alias_method :deregister_instances, :deregister_instances_from_load_balancer + end + end + end +end diff --git a/lib/fog/aws/requests/elb/describe_instance_health.rb b/lib/fog/aws/requests/elb/describe_instance_health.rb new file mode 100644 index 000000000..1dd631276 --- /dev/null +++ b/lib/fog/aws/requests/elb/describe_instance_health.rb @@ -0,0 +1,70 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/describe_instance_health' + + # Get health status for one or more instances on an existing ELB + # + # ==== Parameters + # * lb_name<~String> - Load balancer to check instances health on + # * instance_ids<~Array> - Optional list of instance IDs to check + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeInstanceHealthResult'<~Hash>: + # * 'InstanceStates'<~Array> - array of hashes describing instance health + # * 'Description'<~String> + # * 'State'<~String> + # * 'InstanceId'<~String> + # * 'ReasonCode'<~String> + def describe_instance_health(lb_name, instance_ids = []) + params = Fog::AWS.indexed_param('Instances.member.%d.InstanceId', [*instance_ids]) + request({ + 'Action' => 'DescribeInstanceHealth', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DescribeInstanceHealth.new + }.merge!(params)) + end + end + + class Mock + def describe_instance_health(lb_name, instance_ids = []) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + instance_ids = [*instance_ids] + instance_ids = load_balancer['Instances'].map { |i| i['InstanceId'] } unless instance_ids.any? + data = instance_ids.map do |id| + unless Fog::Compute::AWS::Mock.data[@region][@aws_access_key_id][:instances][id] + raise Fog::AWS::ELB::InvalidInstance + end + + { + 'Description' => "", + 'InstanceId' => id, + 'ReasonCode' => "", + 'State' => 'OutOfService' + } + end + + response = Excon::Response.new + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DescribeInstanceHealthResult' => { + 'InstanceStates' => data + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/describe_load_balancer_attributes.rb b/lib/fog/aws/requests/elb/describe_load_balancer_attributes.rb new file mode 100644 index 000000000..afdcfa195 --- /dev/null +++ b/lib/fog/aws/requests/elb/describe_load_balancer_attributes.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/describe_load_balancer_attributes' + + # Describe the load balancer attributes + # http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_DescribeLoadBalancerAttributes.html + # ==== Parameters + # * lb_name<~String> - The mnemonic name associated with the LoadBalancer. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeLoadBalancerAttributesResult'<~Hash>: + # * 'LoadBalancerAttributes'<~Hash> + # * 'ConnectionDraining'<~Hash> + # * 'Enabled'<~Boolean> - whether connection draining is enabled + # * 'Timeout'<~Integer> - max time (in seconds) to keep existing conns open before deregistering instances. + # * 'CrossZoneLoadBalancing'<~Hash> + # * 'Enabled'<~Boolean> - whether crosszone load balancing is enabled + # * 'ConnectionSettings'<~Hash> + # * 'IdleTimeout'<~Integer> - time (in seconds) the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer. + + def describe_load_balancer_attributes(lb_name) + request({ + 'Action' => 'DescribeLoadBalancerAttributes', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DescribeLoadBalancerAttributes.new + }) + end + end + + class Mock + def describe_load_balancer_attributes(lb_name = nil, names = []) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + attributes = load_balancer['LoadBalancerAttributes'] + + response = Excon::Response.new + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DescribeLoadBalancerAttributesResult' => { + 'LoadBalancerAttributes' => attributes + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/describe_load_balancer_policies.rb b/lib/fog/aws/requests/elb/describe_load_balancer_policies.rb new file mode 100644 index 000000000..5f324ff94 --- /dev/null +++ b/lib/fog/aws/requests/elb/describe_load_balancer_policies.rb @@ -0,0 +1,69 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/describe_load_balancer_policies' + + # Describe all or specified load balancer policies + # + # ==== Parameters + # * lb_name<~String> - The mnemonic name associated with the LoadBalancer. If no name is specified, the operation returns the attributes of either all the sample policies pre-defined by Elastic Load Balancing or the specified sample polices. + # * names<~Array> - The names of LoadBalancer policies you've created or Elastic Load Balancing sample policy names. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeLoadBalancerPoliciesResult'<~Hash>: + # * 'PolicyDescriptions'<~Array> + # * 'PolicyAttributeDescriptions'<~Array> + # * 'AttributeName'<~String> - The name of the attribute associated with the policy. + # * 'AttributeValue'<~String> - The value of the attribute associated with the policy. + # * 'PolicyName'<~String> - The name mof the policy associated with the LoadBalancer. + # * 'PolicyTypeName'<~String> - The name of the policy type. + def describe_load_balancer_policies(lb_name = nil, names = []) + params = Fog::AWS.indexed_param('PolicyNames.member', [*names]) + request({ + 'Action' => 'DescribeLoadBalancerPolicies', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DescribeLoadBalancerPolicies.new + }.merge!(params)) + end + end + + class Mock + def describe_load_balancer_policies(lb_name = nil, names = []) + if lb_name + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + names = [*names] + policies = if names.any? + names.map do |name| + raise Fog::AWS::ELB::PolicyNotFound unless policy = load_balancer['Policies']['Proper'].find { |p| p['PolicyName'] == name } + policy.dup + end.compact + else + load_balancer['Policies']['Proper'] + end + else + policies = [] + end + + response = Excon::Response.new + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DescribeLoadBalancerPoliciesResult' => { + 'PolicyDescriptions' => policies + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/describe_load_balancer_policy_types.rb b/lib/fog/aws/requests/elb/describe_load_balancer_policy_types.rb new file mode 100644 index 000000000..498b3a850 --- /dev/null +++ b/lib/fog/aws/requests/elb/describe_load_balancer_policy_types.rb @@ -0,0 +1,66 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/describe_load_balancer_policy_types' + + # Describe all or specified load balancer policy types + # + # ==== Parameters + # * type_name<~Array> - Specifies the name of the policy types. If no names are specified, returns the description of all the policy types defined by Elastic Load Balancing service. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeLoadBalancerPolicyTypesResult'<~Hash>: + # * 'PolicyTypeDescriptions'<~Array> + # * 'Description'<~String> - A human-readable description of the policy type. + # * 'PolicyAttributeTypeDescriptions'<~Array> + # * 'AttributeName'<~String> - The name of the attribute associated with the policy type. + # * 'AttributeValue'<~String> - The type of attribute. For example, Boolean, Integer, etc. + # * 'Cardinality'<~String> - The cardinality of the attribute. + # * 'DefaultValue'<~String> - The default value of the attribute, if applicable. + # * 'Description'<~String> - A human-readable description of the attribute. + # * 'PolicyTypeName'<~String> - The name of the policy type. + def describe_load_balancer_policy_types(type_names = []) + params = Fog::AWS.indexed_param('PolicyTypeNames.member', [*type_names]) + request({ + 'Action' => 'DescribeLoadBalancerPolicyTypes', + :parser => Fog::Parsers::AWS::ELB::DescribeLoadBalancerPolicyTypes.new + }.merge!(params)) + end + end + + class Mock + def describe_load_balancer_policy_types(type_names = []) + type_names = [*type_names] + policy_types = if type_names.any? + type_names.map do |type_name| + policy_type = self.data[:policy_types].find { |pt| pt['PolicyTypeName'] == type_name } + raise Fog::AWS::ELB::PolicyTypeNotFound unless policy_type + policy_type[1].dup + end.compact + else + self.data[:policy_types].map { |policy_type| policy_type.dup } + end + + response = Excon::Response.new + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DescribeLoadBalancerPolicyTypesResult' => { + 'PolicyTypeDescriptions' => policy_types + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/describe_load_balancers.rb b/lib/fog/aws/requests/elb/describe_load_balancers.rb new file mode 100644 index 000000000..33b48073b --- /dev/null +++ b/lib/fog/aws/requests/elb/describe_load_balancers.rb @@ -0,0 +1,137 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/describe_load_balancers' + + # Describe all or specified load balancers + # + # ==== Parameters + # * options<~Hash> + # * 'LoadBalancerNames'<~Array> - List of load balancer names to describe, defaults to all + # * 'Marker' - Indicates where to begin in your list of load balancers + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DescribeLoadBalancersResult'<~Hash>: + # * 'LoadBalancerDescriptions'<~Array> + # * 'AvailabilityZones'<~Array> - list of availability zones covered by this load balancer + # * 'BackendServerDescriptions'<~Array>: + # * 'InstancePort'<~Integer> - the port on which the back-end server is listening + # * 'PolicyNames'<~Array> - list of policy names enabled for the back-end server + # * 'CanonicalHostedZoneName'<~String> - name of the Route 53 hosted zone associated with the load balancer + # * 'CanonicalHostedZoneNameID'<~String> - ID of the Route 53 hosted zone associated with the load balancer + # * 'CreatedTime'<~Time> - time load balancer was created + # * 'DNSName'<~String> - external DNS name of load balancer + # * 'HealthCheck'<~Hash>: + # * 'HealthyThreshold'<~Integer> - number of consecutive health probe successes required before moving the instance to the Healthy state + # * 'Timeout'<~Integer> - number of seconds after which no response means a failed health probe + # * 'Interval'<~Integer> - interval (in seconds) between health checks of an individual instance + # * 'UnhealthyThreshold'<~Integer> - number of consecutive health probe failures that move the instance to the unhealthy state + # * 'Target'<~String> - string describing protocol type, port and URL to check + # * 'Instances'<~Array> - list of instances that the load balancer balances between + # * 'ListenerDescriptions'<~Array> + # * 'PolicyNames'<~Array> - list of policies enabled + # * 'Listener'<~Hash>: + # * 'InstancePort'<~Integer> - port on instance that requests are sent to + # * 'Protocol'<~String> - transport protocol used for routing in [TCP, HTTP] + # * 'LoadBalancerPort'<~Integer> - port that load balancer listens on for requests + # * 'LoadBalancerName'<~String> - name of load balancer + # * 'Policies'<~Hash>: + # * 'LBCookieStickinessPolicies'<~Array> - list of Load Balancer Generated Cookie Stickiness policies for the LoadBalancer + # * 'AppCookieStickinessPolicies'<~Array> - list of Application Generated Cookie Stickiness policies for the LoadBalancer + # * 'OtherPolicies'<~Array> - list of policy names other than the stickiness policies + # * 'SourceSecurityGroup'<~Hash>: + # * 'GroupName'<~String> - Name of the source security group to use with inbound security group rules + # * 'OwnerAlias'<~String> - Owner of the source security group + # * 'NextMarker'<~String> - Marker to specify for next page + def describe_load_balancers(options = {}) + unless options.is_a?(Hash) + Fog::Logger.deprecation("describe_load_balancers with #{options.class} is deprecated, use all('LoadBalancerNames' => []) instead [light_black](#{caller.first})[/]") + options = { 'LoadBalancerNames' => [options].flatten } + end + + if names = options.delete('LoadBalancerNames') + options.update(Fog::AWS.indexed_param('LoadBalancerNames.member', [*names])) + end + + request({ + 'Action' => 'DescribeLoadBalancers', + :parser => Fog::Parsers::AWS::ELB::DescribeLoadBalancers.new + }.merge!(options)) + end + end + + class Mock + def describe_load_balancers(options = {}) + unless options.is_a?(Hash) + Fog::Logger.deprecation("describe_load_balancers with #{options.class} is deprecated, use all('LoadBalancerNames' => []) instead [light_black](#{caller.first})[/]") + options = { 'LoadBalancerNames' => [options].flatten } + end + + lb_names = options['LoadBalancerNames'] || [] + + lb_names = [*lb_names] + load_balancers = if lb_names.any? + lb_names.map do |lb_name| + lb = self.data[:load_balancers].find { |name, data| name == lb_name } + raise Fog::AWS::ELB::NotFound unless lb + lb[1].dup + end.compact + else + self.data[:load_balancers].map { |lb, values| values.dup } + end + + marker = options.fetch('Marker', 0).to_i + if load_balancers.count - marker > 400 + next_marker = marker + 400 + load_balancers = load_balancers[marker...next_marker] + else + next_marker = nil + end + + response = Excon::Response.new + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DescribeLoadBalancersResult' => { + 'LoadBalancerDescriptions' => load_balancers.map do |lb| + lb['Instances'] = lb['Instances'].map { |i| i['InstanceId'] } + lb['Policies'] = lb['Policies']['Proper'].reduce({'AppCookieStickinessPolicies' => [], 'LBCookieStickinessPolicies' => [], 'OtherPolicies' => []}) { |m, policy| + case policy['PolicyTypeName'] + when 'AppCookieStickinessPolicyType' + cookie_name = policy['PolicyAttributeDescriptions'].find{|h| h['AttributeName'] == 'CookieName'}['AttributeValue'] + m['AppCookieStickinessPolicies'] << { 'PolicyName' => policy['PolicyName'], 'CookieName' => cookie_name } + when 'LBCookieStickinessPolicyType' + cookie_expiration_period = policy['PolicyAttributeDescriptions'].find{|h| h['AttributeName'] == 'CookieExpirationPeriod'}['AttributeValue'].to_i + lb_policy = { 'PolicyName' => policy['PolicyName'] } + lb_policy['CookieExpirationPeriod'] = cookie_expiration_period if cookie_expiration_period > 0 + m['LBCookieStickinessPolicies'] << lb_policy + else + m['OtherPolicies'] << policy['PolicyName'] + end + m + } + + lb['BackendServerDescriptions'] = lb.delete('BackendServerDescriptionsRemote') + lb + end + } + } + + if next_marker + response.body['DescribeLoadBalancersResult']['NextMarker'] = next_marker.to_s + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/describe_tags.rb b/lib/fog/aws/requests/elb/describe_tags.rb new file mode 100644 index 000000000..870e134c3 --- /dev/null +++ b/lib/fog/aws/requests/elb/describe_tags.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class ELB + class Real + + require 'fog/aws/parsers/elb/tag_list_parser' + + # returns a Hash of tags for a load balancer + # http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_DescribeTags.html + # ==== Parameters + # * elb_id <~String> - name(s) of the ELB instance whose tags are to be retrieved (allows 1-20 of them) + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_tags(elb_ids) + request({ + 'Action' => 'DescribeTags', + :parser => Fog::Parsers::AWS::ELB::TagListParser.new + }.merge(Fog::AWS.indexed_param('LoadBalancerNames.member.%d', elb_ids)) + ) + end + # def describe_tags(filters = {}) + # params = Fog::AWS.indexed_filters(filters) + # request({ + # 'Action' => 'DescribeTags', + # :idempotent => true, + # :parser => Fog::Parsers::Compute::AWS::DescribeTags.new + # }.merge!(params)) + # end + + end + + class Mock + + def describe_tags(elb_id) + response = Excon::Response.new + + if server = self.data[:load_balancers][elb_id] + response.status = 200 + ##{"DescribeTagsResult"=>{"LoadBalancers"=>[{"Tags"=>{"Name"=>"2esakowski-test-opsworks-elb"}, "LoadBalancerName"=>"esakowski-test-opsworks"}]}} + response.body = {"DescribeTagsResult"=>{"LoadBalancers"=>[{"Tags"=>self.data[:tags][elb_id], "LoadBalancerName"=>elb_id}]}} + +# response.body = { +# "DescribeTagsResult" => +# {"TagDescriptions" => self.data[:tags][elb_id]} +# } + response + else + raise Fog::AWS::ELB::NotFound.new("Elastic load balancer #{elb_id} not found") + end + end + + end + end + end +end diff --git a/lib/fog/aws/requests/elb/detach_load_balancer_from_subnets.rb b/lib/fog/aws/requests/elb/detach_load_balancer_from_subnets.rb new file mode 100644 index 000000000..c92aa37a5 --- /dev/null +++ b/lib/fog/aws/requests/elb/detach_load_balancer_from_subnets.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/detach_load_balancer_from_subnets' + + # Disable a subnet for an existing ELB + # + # ==== Parameters + # * subnet_ids<~Array> - List of subnet ids to enable on ELB + # * lb_name<~String> - Load balancer to disable availability zones on + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DetachLoadBalancerFromSubnetsResult'<~Hash>: + # * 'Subnets'<~Array> - array of strings describing the subnet ids currently enabled + def detach_load_balancer_from_subnets(subnet_ids, lb_name) + params = Fog::AWS.indexed_param('Subnets.member', [*subnet_ids]) + request({ + 'Action' => 'DetachLoadBalancerFromSubnets', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DetachLoadBalancerFromSubnets.new + }.merge!(params)) + end + + alias_method :disable_subnets, :detach_load_balancer_from_subnets + end + + class Mock + def detach_load_balancer_from_subnets(subnet_ids, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + response = Excon::Response.new + response.status = 200 + + load_balancer['Subnets'] << subnet_ids + load_balancer['Subnets'].flatten!.uniq! + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DetachLoadBalancerFromSubnetsResult' => { + 'Subnets' => load_balancer['Subnets'] + } + } + + response + end + + alias_method :disable_subnets, :detach_load_balancer_from_subnets + end + end + end +end diff --git a/lib/fog/aws/requests/elb/disable_availability_zones_for_load_balancer.rb b/lib/fog/aws/requests/elb/disable_availability_zones_for_load_balancer.rb new file mode 100644 index 000000000..6556d15fd --- /dev/null +++ b/lib/fog/aws/requests/elb/disable_availability_zones_for_load_balancer.rb @@ -0,0 +1,57 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/disable_availability_zones_for_load_balancer' + + # Disable an availability zone for an existing ELB + # + # ==== Parameters + # * availability_zones<~Array> - List of availability zones to disable on ELB + # * lb_name<~String> - Load balancer to disable availability zones on + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'DisableAvailabilityZonesForLoadBalancerResult'<~Hash>: + # * 'AvailabilityZones'<~Array> - A list of updated Availability Zones for the LoadBalancer. + def disable_availability_zones_for_load_balancer(availability_zones, lb_name) + params = Fog::AWS.indexed_param('AvailabilityZones.member', [*availability_zones]) + request({ + 'Action' => 'DisableAvailabilityZonesForLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::DisableAvailabilityZonesForLoadBalancer.new + }.merge!(params)) + end + + alias_method :disable_zones, :disable_availability_zones_for_load_balancer + end + + class Mock + def disable_availability_zones_for_load_balancer(availability_zones, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + response = Excon::Response.new + response.status = 200 + + load_balancer['AvailabilityZones'].delete_if { |az| availability_zones.include? az } + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'DisableAvailabilityZonesForLoadBalancerResult' => { + 'AvailabilityZones' => load_balancer['AvailabilityZones'] + } + } + + response + end + + alias_method :disable_zones, :disable_availability_zones_for_load_balancer + end + end + end +end diff --git a/lib/fog/aws/requests/elb/enable_availability_zones_for_load_balancer.rb b/lib/fog/aws/requests/elb/enable_availability_zones_for_load_balancer.rb new file mode 100644 index 000000000..d830d25f6 --- /dev/null +++ b/lib/fog/aws/requests/elb/enable_availability_zones_for_load_balancer.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/enable_availability_zones_for_load_balancer' + + # Enable an availability zone for an existing ELB + # + # ==== Parameters + # * availability_zones<~Array> - List of availability zones to enable on ELB + # * lb_name<~String> - Load balancer to enable availability zones on + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'EnableAvailabilityZonesForLoadBalancerResult'<~Hash>: + # * 'AvailabilityZones'<~Array> - array of strings describing instances currently enabled + def enable_availability_zones_for_load_balancer(availability_zones, lb_name) + params = Fog::AWS.indexed_param('AvailabilityZones.member', [*availability_zones]) + request({ + 'Action' => 'EnableAvailabilityZonesForLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::EnableAvailabilityZonesForLoadBalancer.new + }.merge!(params)) + end + + alias_method :enable_zones, :enable_availability_zones_for_load_balancer + end + + class Mock + def enable_availability_zones_for_load_balancer(availability_zones, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + response = Excon::Response.new + response.status = 200 + + load_balancer['AvailabilityZones'] << availability_zones + load_balancer['AvailabilityZones'].flatten!.uniq! + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'EnableAvailabilityZonesForLoadBalancerResult' => { + 'AvailabilityZones' => load_balancer['AvailabilityZones'] + } + } + + response + end + + alias_method :enable_zones, :enable_availability_zones_for_load_balancer + end + end + end +end diff --git a/lib/fog/aws/requests/elb/modify_load_balancer_attributes.rb b/lib/fog/aws/requests/elb/modify_load_balancer_attributes.rb new file mode 100644 index 000000000..e2e41a021 --- /dev/null +++ b/lib/fog/aws/requests/elb/modify_load_balancer_attributes.rb @@ -0,0 +1,65 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Sets attributes of the load balancer + # + # The following attributes can be set: + # * CrossZoneLoadBalancing (enable/disable) + # * ConnectionDraining (enable/disable and timeout) + # * Idle Connection Timeouts + # + # Still requires: AccessLog configuration + # + # http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_ModifyLoadBalancerAttributes.html + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * options<~Hash> + # * 'ConnectionDraining'<~Hash>: + # * 'Enabled'<~Boolean> whether to enable connection draining + # * 'Timeout'<~Integer> max time to keep existing conns open before deregistering instances + # * 'CrossZoneLoadBalancing'<~Hash>: + # * 'Enabled'<~Boolean> whether to enable cross zone load balancing + # * 'ConnectionSettings'<~Hash>: + # * 'IdleTimeout'<~Integer> time (in seconds) the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def modify_load_balancer_attributes(lb_name, options) + attributes = Fog::AWS.serialize_keys 'LoadBalancerAttributes', options + request(attributes.merge( + 'Action' => 'ModifyLoadBalancerAttributes', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + )) + end + end + + class Mock + def modify_load_balancer_attributes(lb_name, attributes) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + if attributes['CrossZoneLoadBalancing'] || attributes['ConnectionDraining'] || attributes['ConnectionSettings'] + load_balancer['LoadBalancerAttributes'].merge! attributes + end + + response = Excon::Response.new + + response.status = 200 + response.body = { + "ResponseMetadata" => { + "RequestId" => Fog::AWS::Mock.request_id + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/register_instances_with_load_balancer.rb b/lib/fog/aws/requests/elb/register_instances_with_load_balancer.rb new file mode 100644 index 000000000..f78aea260 --- /dev/null +++ b/lib/fog/aws/requests/elb/register_instances_with_load_balancer.rb @@ -0,0 +1,62 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/register_instances_with_load_balancer' + + # Register an instance with an existing ELB + # + # ==== Parameters + # * instance_ids<~Array> - List of instance IDs to associate with ELB + # * lb_name<~String> - Load balancer to assign instances to + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + # * 'RegisterInstancesWithLoadBalancerResult'<~Hash>: + # * 'Instances'<~Array> - array of hashes describing instances currently enabled + # * 'InstanceId'<~String> + def register_instances_with_load_balancer(instance_ids, lb_name) + params = Fog::AWS.indexed_param('Instances.member.%d.InstanceId', [*instance_ids]) + request({ + 'Action' => 'RegisterInstancesWithLoadBalancer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::RegisterInstancesWithLoadBalancer.new + }.merge!(params)) + end + + alias_method :register_instances, :register_instances_with_load_balancer + end + + class Mock + def register_instances_with_load_balancer(instance_ids, lb_name) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + instance_ids = [*instance_ids] + instances = instance_ids.map do |instance| + raise Fog::AWS::ELB::InvalidInstance unless Fog::Compute::AWS::Mock.data[@region][@aws_access_key_id][:instances][instance] + {'InstanceId' => instance} + end + + response = Excon::Response.new + response.status = 200 + + load_balancer['Instances'] = load_balancer['Instances'] | instances.dup + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'RegisterInstancesWithLoadBalancerResult' => { + 'Instances' => instances + } + } + + response + end + alias_method :register_instances, :register_instances_with_load_balancer + end + end + end +end diff --git a/lib/fog/aws/requests/elb/remove_tags.rb b/lib/fog/aws/requests/elb/remove_tags.rb new file mode 100644 index 000000000..4268ed923 --- /dev/null +++ b/lib/fog/aws/requests/elb/remove_tags.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class ELB + class Real + + # removes tags from an elastic load balancer instance + # http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_RemoveTags.html + # ==== Parameters + # * elb_id <~String> - name of the ELB instance whose tags are to be retrieved + # * keys <~Array> A list of String keys for the tags to remove + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def remove_tags(elb_id, keys) + request( + { 'Action' => 'RemoveTags', + # Note: there is a discrepancy in the API docs in the ID parameter name between the write-up and the example. + # Who knows which way the fix will go, if any is ever made? In any case, this works. + 'LoadBalancerNames.member.1' => elb_id, + :parser => Fog::Parsers::AWS::ELB::Empty.new, + }.merge(Fog::AWS.indexed_param('Tags.member.%d.Key', keys)) + ) + end + + end + + class Mock + + def remove_tags(elb_id, keys) + response = Excon::Response.new + if server = self.data[:load_balancers][elb_id] + keys.each {|key| self.data[:tags][elb_id].delete key} + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id } + } + response + else + raise Fog::AWS::ELB::NotFound.new("Elastic load balancer #{elb_id} not found") + end + end + + end + end + end +end diff --git a/lib/fog/aws/requests/elb/set_load_balancer_listener_ssl_certificate.rb b/lib/fog/aws/requests/elb/set_load_balancer_listener_ssl_certificate.rb new file mode 100644 index 000000000..634ac4484 --- /dev/null +++ b/lib/fog/aws/requests/elb/set_load_balancer_listener_ssl_certificate.rb @@ -0,0 +1,65 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Sets the certificate that terminates the specified listener's SSL + # connections. The specified certificate replaces any prior certificate + # that was used on the same LoadBalancer and port. + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * load_balancer_port<~Integer> - The external port of the LoadBalancer + # with which this policy has to be associated. + # * ssl_certificate_id<~String> - ID of the SSL certificate chain to use + # example: arn:aws:iam::322191361670:server-certificate/newCert + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def set_load_balancer_listener_ssl_certificate(lb_name, load_balancer_port, ssl_certificate_id) + request({ + 'Action' => 'SetLoadBalancerListenerSSLCertificate', + 'LoadBalancerName' => lb_name, + 'LoadBalancerPort' => load_balancer_port, + 'SSLCertificateId' => ssl_certificate_id, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }) + end + end + + class Mock + def set_load_balancer_listener_ssl_certificate(lb_name, load_balancer_port, ssl_certificate_id) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + certificate_ids = Fog::AWS::IAM::Mock.data[@aws_access_key_id][:server_certificates].map {|n, c| c['Arn'] } + if !certificate_ids.include? ssl_certificate_id + raise Fog::AWS::IAM::NotFound.new('CertificateNotFound') + end + + response = Excon::Response.new + + unless listener = load_balancer['ListenerDescriptions'].find { |listener| listener['Listener']['LoadBalancerPort'] == load_balancer_port } + response.status = 400 + response.body = "ListenerNotFoundLoadBalancer does not have a listnener configured at the given port.#{Fog::AWS::Mock.request_id}" + raise Excon::Errors.status_error({:expects => 200}, response) + end + + listener['Listener']['SSLCertificateId'] = ssl_certificate_id + + response.status = 200 + response.body = { + "ResponseMetadata" => { + "RequestId" => Fog::AWS::Mock.request_id + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/set_load_balancer_policies_for_backend_server.rb b/lib/fog/aws/requests/elb/set_load_balancer_policies_for_backend_server.rb new file mode 100644 index 000000000..43d1859d5 --- /dev/null +++ b/lib/fog/aws/requests/elb/set_load_balancer_policies_for_backend_server.rb @@ -0,0 +1,66 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Replaces the current set of policies associated with a port on which the back-end server is listening with a new set of policies. + # After the policies have been created using CreateLoadBalancerPolicy, they can be applied here as a list. + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * instance_port<~Integer> - The port on the instance that the ELB will forward traffic to + # * policy_names<~Array> - Array of Strings listing the policies to set for the backend port + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def set_load_balancer_policies_for_backend_server(lb_name, instance_port, policy_names) + params = {'InstancePort' => instance_port} + if policy_names.any? + params.merge!(Fog::AWS.indexed_param('PolicyNames.member', policy_names)) + else + params['PolicyNames'] = '' + end + + request({ 'Action' => 'SetLoadBalancerPoliciesForBackendServer', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def set_load_balancer_policies_for_backend_server(lb_name, instance_port, policy_names) + if load_balancer = self.data[:load_balancers][lb_name] + # Ensure policies exist + policy_names.each do |policy_name| + unless load_balancer['Policies']['Proper'].find { |p| p['PolicyName'] == policy_name } + raise Fog::AWS::ELB::PolicyNotFound, "There is no policy with name #{policy_name} for load balancer #{lb_name}" + end + end + + # Update backend policies: + description = load_balancer['BackendServerDescriptionsRemote'].find{|d| d["InstancePort"] == instance_port } || {} + description["InstancePort"] = instance_port + description["PolicyNames"] = policy_names + load_balancer['BackendServerDescriptionsRemote'].delete_if{|d| d["InstancePort"] == instance_port } + load_balancer['BackendServerDescriptionsRemote'] << description + + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + end + else + raise Fog::AWS::ELB::NotFound + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elb/set_load_balancer_policies_of_listener.rb b/lib/fog/aws/requests/elb/set_load_balancer_policies_of_listener.rb new file mode 100644 index 000000000..73054aa0d --- /dev/null +++ b/lib/fog/aws/requests/elb/set_load_balancer_policies_of_listener.rb @@ -0,0 +1,78 @@ +module Fog + module AWS + class ELB + class Real + require 'fog/aws/parsers/elb/empty' + + # Associates, updates, or disables a policy with a listener on the + # load balancer. Currently only zero (0) or one (1) policy can be + # associated with a listener. + # + # ==== Parameters + # * lb_name<~String> - Name of the ELB + # * load_balancer_port<~Integer> - The external port of the LoadBalancer + # with which this policy has to be associated. + + # * policy_names<~Array> - List of policies to be associated with the + # listener. Currently this list can have at most one policy. If the + # list is empty, the current policy is removed from the listener. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def set_load_balancer_policies_of_listener(lb_name, load_balancer_port, policy_names) + params = {'LoadBalancerPort' => load_balancer_port} + if policy_names.any? + params.merge!(Fog::AWS.indexed_param('PolicyNames.member', policy_names)) + else + params['PolicyNames'] = '' + end + + request({ + 'Action' => 'SetLoadBalancerPoliciesOfListener', + 'LoadBalancerName' => lb_name, + :parser => Fog::Parsers::AWS::ELB::Empty.new + }.merge!(params)) + end + end + + class Mock + def set_load_balancer_policies_of_listener(lb_name, load_balancer_port, policy_names) + raise Fog::AWS::ELB::NotFound unless load_balancer = self.data[:load_balancers][lb_name] + + policy_names = [*policy_names] + response = Excon::Response.new + if policy_names.size > 1 + response.status = 409 + response.body = "InvalidConfigurationRequestRequested configuration change is invalid.#{Fog::AWS::Mock.request_id}" + raise Excon::Errors.status_error({:expects => 200}, response) + end + + unless listener = load_balancer['ListenerDescriptions'].find { |listener| listener['Listener']['LoadBalancerPort'] == load_balancer_port } + response.status = 400 + response.body = "ListenerNotFoundLoadBalancer does not have a listnener configured at the given port.#{Fog::AWS::Mock.request_id}" + raise Excon::Errors.status_error({:expects => 200}, response) + end + + unless load_balancer['Policies']['Proper'].find { |policy| policy['PolicyName'] == policy_names.first } + response.status = 400 + response.body = "PolicyNotFoundOne or more specified policies were not found.#{Fog::AWS::Mock.request_id}" + raise Excon::Errors.status_error({:expects => 200}, response) + end if policy_names.any? + + listener['PolicyNames'] = policy_names + + response.status = 200 + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/add_instance_groups.rb b/lib/fog/aws/requests/emr/add_instance_groups.rb new file mode 100644 index 000000000..7e26cb10b --- /dev/null +++ b/lib/fog/aws/requests/emr/add_instance_groups.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/add_instance_groups' + + # adds an instance group to a running cluster + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_AddInstanceGroups.html + # ==== Parameters + # * JobFlowId <~String> - Job flow in which to add the instance groups + # * InstanceGroups<~Array> - Instance Groups to add + # * 'BidPrice'<~String> - Bid price for each Amazon EC2 instance in the instance group when launching nodes as Spot Instances, expressed in USD. + # * 'InstanceCount'<~Integer> - Target number of instances for the instance group + # * 'InstanceRole'<~String> - MASTER | CORE | TASK The role of the instance group in the cluster + # * 'InstanceType'<~String> - The Amazon EC2 instance type for all instances in the instance group + # * 'MarketType'<~String> - ON_DEMAND | SPOT Market type of the Amazon EC2 instances used to create a cluster node + # * 'Name'<~String> - Friendly name given to the instance group. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def add_instance_groups(job_flow_id, options={}) + if instance_groups = options.delete('InstanceGroups') + options.merge!(Fog::AWS.indexed_param('InstanceGroups.member.%d', [*instance_groups])) + end + + request({ + 'Action' => 'AddInstanceGroups', + 'JobFlowId' => job_flow_id, + :parser => Fog::Parsers::AWS::EMR::AddInstanceGroups.new, + }.merge(options)) + end + end + + class Mock + def add_instance_groups(job_flow_id, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/add_job_flow_steps.rb b/lib/fog/aws/requests/emr/add_job_flow_steps.rb new file mode 100644 index 000000000..60319ed01 --- /dev/null +++ b/lib/fog/aws/requests/emr/add_job_flow_steps.rb @@ -0,0 +1,45 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/add_job_flow_steps' + + # adds new steps to a running job flow. + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_AddJobFlowSteps.html + # ==== Parameters + # * JobFlowId <~String> - A string that uniquely identifies the job flow + # * Steps <~Array> - A list of steps to be executed by the job flow + # * 'ActionOnFailure'<~String> - TERMINATE_JOB_FLOW | CANCEL_AND_WAIT | CONTINUE Specifies the action to take if the job flow step fails + # * 'HadoopJarStep'<~Array> - Specifies the JAR file used for the job flow step + # * 'Args'<~String list> - A list of command line arguments passed to the JAR file's main function when executed. + # * 'Jar'<~String> - A path to a JAR file run during the step. + # * 'MainClass'<~String> - The name of the main class in the specified Java file. If not specified, the JAR file should specify a Main-Class in its manifest file + # * 'Properties'<~Array> - A list of Java properties that are set when the step runs. You can use these properties to pass key value pairs to your main function + # * 'Key'<~String> - The unique identifier of a key value pair + # * 'Value'<~String> - The value part of the identified key + # * 'Name'<~String> - The name of the job flow step + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def add_job_flow_steps(job_flow_id, options={}) + if steps = options.delete('Steps') + options.merge!(Fog::AWS.serialize_keys('Steps', steps)) + end + + request({ + 'Action' => 'AddJobFlowSteps', + 'JobFlowId' => job_flow_id, + :parser => Fog::Parsers::AWS::EMR::AddJobFlowSteps.new, + }.merge(options)) + end + end + + class Mock + def add_job_flow_steps(db_name, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/describe_job_flows.rb b/lib/fog/aws/requests/emr/describe_job_flows.rb new file mode 100644 index 000000000..9a41fcacd --- /dev/null +++ b/lib/fog/aws/requests/emr/describe_job_flows.rb @@ -0,0 +1,104 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/describe_job_flows' + + # returns a list of job flows that match all of the supplied parameters. + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_DescribeJobFlows.html + # ==== Parameters + # * CreatedAfter <~DateTime> - Return only job flows created after this date and time + # * CreatedBefore <~DateTime> - Return only job flows created before this date and time + # * JobFlowIds <~String list> - Return only job flows whose job flow ID is contained in this list + # * JobFlowStates <~String list> - RUNNING | WAITING | SHUTTING_DOWN | STARTING Return only job flows whose state is contained in this list + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * JobFlows <~Array> - A list of job flows matching the parameters supplied. + # * AmiVersion <~String> - A list of bootstrap actions that will be run before Hadoop is started on the cluster nodes. + # * 'BootstrapActions'<~Array> - A list of the bootstrap actions run by the job flow + # * 'BootstrapConfig <~Array> - A description of the bootstrap action + # * 'Name' <~String> - The name of the bootstrap action + # * 'ScriptBootstrapAction' <~Array> - The script run by the bootstrap action. + # * 'Args' <~String list> - A list of command line arguments to pass to the bootstrap action script. + # * 'Path' <~String> - Location of the script to run during a bootstrap action. + # * 'ExecutionStatusDetail'<~Array> - Describes the execution status of the job flow + # * 'CreationDateTime <~DateTime> - The creation date and time of the job flow. + # * 'EndDateTime <~DateTime> - The completion date and time of the job flow. + # * 'LastStateChangeReason <~String> - Description of the job flow last changed state. + # * 'ReadyDateTime <~DateTime> - The date and time when the job flow was ready to start running bootstrap actions. + # * 'StartDateTime <~DateTime> - The start date and time of the job flow. + # * 'State <~DateTime> - COMPLETED | FAILED | TERMINATED | RUNNING | SHUTTING_DOWN | STARTING | WAITING | BOOTSTRAPPING The state of the job flow. + # * Instances <~Array> - A specification of the number and type of Amazon EC2 instances on which to run the job flow. + # * 'Ec2KeyName'<~String> - Specifies the name of the Amazon EC2 key pair that can be used to ssh to the master node as the user called "hadoop. + # * 'HadoopVersion'<~String> - "0.18" | "0.20" Specifies the Hadoop version for the job flow + # * 'InstanceCount'<~Integer> - The number of Amazon EC2 instances used to execute the job flow + # * 'InstanceGroups'<~Array> - Configuration for the job flow's instance groups + # * 'BidPrice' <~String> - Bid price for each Amazon EC2 instance in the instance group when launching nodes as Spot Instances, expressed in USD. + # * 'CreationDateTime' <~DateTime> - The date/time the instance group was created. + # * 'EndDateTime' <~DateTime> - The date/time the instance group was terminated. + # * 'InstanceGroupId' <~String> - Unique identifier for the instance group. + # * 'InstanceRequestCount'<~Integer> - Target number of instances for the instance group + # * 'InstanceRole'<~String> - MASTER | CORE | TASK The role of the instance group in the cluster + # * 'InstanceRunningCount'<~Integer> - Actual count of running instances + # * 'InstanceType'<~String> - The Amazon EC2 instance type for all instances in the instance group + # * 'LastStateChangeReason'<~String> - Details regarding the state of the instance group + # * 'Market'<~String> - ON_DEMAND | SPOT Market type of the Amazon EC2 instances used to create a cluster + # * 'Name'<~String> - Friendly name for the instance group + # * 'ReadyDateTime'<~DateTime> - The date/time the instance group was available to the cluster + # * 'StartDateTime'<~DateTime> - The date/time the instance group was started + # * 'State'<~String> - PROVISIONING | STARTING | BOOTSTRAPPING | RUNNING | RESIZING | ARRESTED | SHUTTING_DOWN | TERMINATED | FAILED | ENDED State of instance group + # * 'KeepJobFlowAliveWhenNoSteps' <~Boolean> - Specifies whether the job flow should terminate after completing all steps + # * 'MasterInstanceId'<~String> - The Amazon EC2 instance identifier of the master node + # * 'MasterInstanceType'<~String> - The EC2 instance type of the master node + # * 'MasterPublicDnsName'<~String> - The DNS name of the master node + # * 'NormalizedInstanceHours'<~Integer> - An approximation of the cost of the job flow, represented in m1.small/hours. + # * 'Placement'<~Array> - Specifies the Availability Zone the job flow will run in + # * 'AvailabilityZone' <~String> - The Amazon EC2 Availability Zone for the job flow. + # * 'SlaveInstanceType'<~String> - The EC2 instance type of the slave nodes + # * 'TerminationProtected'<~Boolean> - Specifies whether to lock the job flow to prevent the Amazon EC2 instances from being terminated by API call, user intervention, or in the event of a job flow error + # * LogUri <~String> - Specifies the location in Amazon S3 to write the log files of the job flow. If a value is not provided, logs are not created + # * Name <~String> - The name of the job flow + # * Steps <~Array> - A list of steps to be executed by the job flow + # * 'ExecutionStatusDetail'<~Array> - Describes the execution status of the job flow + # * 'CreationDateTime <~DateTime> - The creation date and time of the job flow. + # * 'EndDateTime <~DateTime> - The completion date and time of the job flow. + # * 'LastStateChangeReason <~String> - Description of the job flow last changed state. + # * 'ReadyDateTime <~DateTime> - The date and time when the job flow was ready to start running bootstrap actions. + # * 'StartDateTime <~DateTime> - The start date and time of the job flow. + # * 'State <~DateTime> - COMPLETED | FAILED | TERMINATED | RUNNING | SHUTTING_DOWN | STARTING | WAITING | BOOTSTRAPPING The state of the job flow. + # * StepConfig <~Array> - The step configuration + # * 'ActionOnFailure'<~String> - TERMINATE_JOB_FLOW | CANCEL_AND_WAIT | CONTINUE Specifies the action to take if the job flow step fails + # * 'HadoopJarStep'<~Array> - Specifies the JAR file used for the job flow step + # * 'Args'<~String list> - A list of command line arguments passed to the JAR file's main function when executed. + # * 'Jar'<~String> - A path to a JAR file run during the step. + # * 'MainClass'<~String> - The name of the main class in the specified Java file. If not specified, the JAR file should specify a Main-Class in its manifest file + # * 'Properties'<~Array> - A list of Java properties that are set when the step runs. You can use these properties to pass key value pairs to your main function + # * 'Key'<~String> - The unique identifier of a key value pair + # * 'Value'<~String> - The value part of the identified key + # * 'Name'<~String> - The name of the job flow step + def describe_job_flows(options={}) + if job_ids = options.delete('JobFlowIds') + options.merge!(Fog::AWS.serialize_keys('JobFlowIds', job_ids)) + end + + if job_states = options.delete('JobFlowStates') + options.merge!(Fog::AWS.serialize_keys('JobFlowStates', job_states)) + end + + request({ + 'Action' => 'DescribeJobFlows', + :parser => Fog::Parsers::AWS::EMR::DescribeJobFlows.new, + }.merge(options)) + end + end + + class Mock + def describe_job_flows(db_name, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/modify_instance_groups.rb b/lib/fog/aws/requests/emr/modify_instance_groups.rb new file mode 100644 index 000000000..5adb73f4f --- /dev/null +++ b/lib/fog/aws/requests/emr/modify_instance_groups.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/modify_instance_groups' + + # modifies the number of nodes and configuration settings of an instance group.. + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_ModifyInstanceGroups.html + # ==== Parameters + # * InstanceGroups <~InstanceGroupModifyConfig list> - Instance groups to change + # * InstanceCount <~Integer> - Target size for instance group + # * InstanceGroupId <~String> - Unique ID of the instance group to expand or shrink + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash> + def modify_instance_groups(options={}) + if job_ids = options.delete('InstanceGroups') + options.merge!(Fog::AWS.serialize_keys('InstanceGroups', job_ids)) + end + + request({ + 'Action' => 'ModifyInstanceGroups', + :parser => Fog::Parsers::AWS::EMR::ModifyInstanceGroups.new, + }.merge(options)) + end + end + + class Mock + def modify_instance_groups(options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/run_job_flow.rb b/lib/fog/aws/requests/emr/run_job_flow.rb new file mode 100644 index 000000000..21156a6f2 --- /dev/null +++ b/lib/fog/aws/requests/emr/run_job_flow.rb @@ -0,0 +1,104 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/run_job_flow' + + # creates and starts running a new job flow + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_RunJobFlow.html + # ==== Parameters + # * AdditionalInfo <~String> - A JSON string for selecting additional features. + # * BootstrapActions <~Array> - A list of bootstrap actions that will be run before Hadoop is started on the cluster nodes. + # * 'Name'<~String> - The name of the bootstrap action + # * 'ScriptBootstrapAction'<~Array> - The script run by the bootstrap action + # * 'Args' <~Array> - A list of command line arguments to pass to the bootstrap action script + # * 'Path' <~String> - Location of the script to run during a bootstrap action. Can be either a location in Amazon S3 or on a local file system. + # * Instances <~Array> - A specification of the number and type of Amazon EC2 instances on which to run the job flow. + # * 'Ec2KeyName'<~String> - Specifies the name of the Amazon EC2 key pair that can be used to ssh to the master node as the user called "hadoop. + # * 'HadoopVersion'<~String> - "0.18" | "0.20" Specifies the Hadoop version for the job flow + # * 'InstanceCount'<~Integer> - The number of Amazon EC2 instances used to execute the job flow + # * 'InstanceGroups'<~Array> - Configuration for the job flow's instance groups + # * 'BidPrice' <~String> - Bid price for each Amazon EC2 instance in the instance group when launching nodes as Spot Instances, expressed in USD. + # * 'InstanceCount'<~Integer> - Target number of instances for the instance group + # * 'InstanceRole'<~String> - MASTER | CORE | TASK The role of the instance group in the cluster + # * 'InstanceType'<~String> - The Amazon EC2 instance type for all instances in the instance group + # * 'MarketType'<~String> - ON_DEMAND | SPOT Market type of the Amazon EC2 instances used to create a cluster node + # * 'Name'<~String> - Friendly name given to the instance group. + # * 'KeepJobFlowAliveWhenNoSteps' <~Boolean> - Specifies whether the job flow should terminate after completing all steps + # * 'MasterInstanceType'<~String> - The EC2 instance type of the master node + # * 'Placement'<~Array> - Specifies the Availability Zone the job flow will run in + # * 'AvailabilityZone' <~String> - The Amazon EC2 Availability Zone for the job flow. + # * 'SlaveInstanceType'<~String> - The EC2 instance type of the slave nodes + # * 'TerminationProtected'<~Boolean> - Specifies whether to lock the job flow to prevent the Amazon EC2 instances from being terminated by API call, user intervention, or in the event of a job flow error + # * LogUri <~String> - Specifies the location in Amazon S3 to write the log files of the job flow. If a value is not provided, logs are not created + # * Name <~String> - The name of the job flow + # * Steps <~Array> - A list of steps to be executed by the job flow + # * 'ActionOnFailure'<~String> - TERMINATE_JOB_FLOW | CANCEL_AND_WAIT | CONTINUE Specifies the action to take if the job flow step fails + # * 'HadoopJarStep'<~Array> - Specifies the JAR file used for the job flow step + # * 'Args'<~String list> - A list of command line arguments passed to the JAR file's main function when executed. + # * 'Jar'<~String> - A path to a JAR file run during the step. + # * 'MainClass'<~String> - The name of the main class in the specified Java file. If not specified, the JAR file should specify a Main-Class in its manifest file + # * 'Properties'<~Array> - A list of Java properties that are set when the step runs. You can use these properties to pass key value pairs to your main function + # * 'Key'<~String> - The unique identifier of a key value pair + # * 'Value'<~String> - The value part of the identified key + # * 'Name'<~String> - The name of the job flow step + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def run_job_flow(name, options={}) + if bootstrap_actions = options.delete('BootstrapActions') + options.merge!(Fog::AWS.serialize_keys('BootstrapActions', bootstrap_actions)) + end + + if instances = options.delete('Instances') + options.merge!(Fog::AWS.serialize_keys('Instances', instances)) + end + + if steps = options.delete('Steps') + options.merge!(Fog::AWS.serialize_keys('Steps', steps)) + end + + request({ + 'Action' => 'RunJobFlow', + 'Name' => name, + :parser => Fog::Parsers::AWS::EMR::RunJobFlow.new, + }.merge(options)) + end + + def run_hive(name, options={}) + steps = [] + steps << { + 'Name' => 'Setup Hive', + 'HadoopJarStep' => { + 'Jar' => 's3://us-east-1.elasticmapreduce/libs/script-runner/script-runner.jar', + 'Args' => ['s3://us-east-1.elasticmapreduce/libs/hive/hive-script', '--base-path', 's3://us-east-1.elasticmapreduce/libs/hive/', '--install-hive']}, + 'ActionOnFailure' => 'TERMINATE_JOB_FLOW' + } + + # To add a configuration step to the Hive flow, see the step below + # steps << { + # 'Name' => 'Install Hive Site Configuration', + # 'HadoopJarStep' => { + # 'Jar' => 's3://us-east-1.elasticmapreduce/libs/script-runner/script-runner.jar', + # 'Args' => ['s3://us-east-1.elasticmapreduce/libs/hive/hive-script', '--base-path', 's3://us-east-1.elasticmapreduce/libs/hive/', '--install-hive-site', '--hive-site=s3://my.bucket/hive/hive-site.xml']}, + # 'ActionOnFailure' => 'TERMINATE_JOB_FLOW' + # } + options['Steps'] = steps + + if not options['Instances'].nil? + options['Instances']['KeepJobFlowAliveWhenNoSteps'] = true + end + + run_job_flow name, options + end + end + + class Mock + def run_job_flow(db_name, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/set_termination_protection.rb b/lib/fog/aws/requests/emr/set_termination_protection.rb new file mode 100644 index 000000000..85ddd17d5 --- /dev/null +++ b/lib/fog/aws/requests/emr/set_termination_protection.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/set_termination_protection' + + # locks a job flow so the Amazon EC2 instances in the cluster cannot be terminated by user intervention. + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_SetTerminationProtection.html + # ==== Parameters + # * JobFlowIds <~String list> - list of strings that uniquely identify the job flows to protect + # * TerminationProtected <~Boolean> - indicates whether to protect the job flow + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash> + def set_termination_protection(is_protected, options={}) + if job_ids = options.delete('JobFlowIds') + options.merge!(Fog::AWS.serialize_keys('JobFlowIds', job_ids)) + end + request({ + 'Action' => 'SetTerminationProtection', + 'TerminationProtected' => is_protected, + :parser => Fog::Parsers::AWS::EMR::SetTerminationProtection.new, + }.merge(options)) + end + end + + class Mock + def set_termination_protection(db_name, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/emr/terminate_job_flows.rb b/lib/fog/aws/requests/emr/terminate_job_flows.rb new file mode 100644 index 000000000..4a67cbf9b --- /dev/null +++ b/lib/fog/aws/requests/emr/terminate_job_flows.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class EMR + class Real + require 'fog/aws/parsers/emr/terminate_job_flows' + + # shuts a list of job flows down. + # http://docs.amazonwebservices.com/ElasticMapReduce/latest/API/API_TerminateJobFlows.html + # ==== Parameters + # * JobFlowIds <~String list> - list of strings that uniquely identify the job flows to protect + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash> + def terminate_job_flows(options={}) + if job_ids = options.delete('JobFlowIds') + options.merge!(Fog::AWS.serialize_keys('JobFlowIds', job_ids)) + end + request({ + 'Action' => 'TerminateJobFlows', + :parser => Fog::Parsers::AWS::EMR::TerminateJobFlows.new, + }.merge(options)) + end + end + + class Mock + def terminate_job_flows(db_name, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/abort_multipart_upload.rb b/lib/fog/aws/requests/glacier/abort_multipart_upload.rb new file mode 100644 index 000000000..efd5d33e8 --- /dev/null +++ b/lib/fog/aws/requests/glacier/abort_multipart_upload.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class Glacier + class Real + # Abort an upload + # + # ==== Parameters + # * name<~String> Name of the vault to upload to + # * upload_id<~String> The id of the upload to complete + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-multipart-abort-upload.html + # + def abort_multipart_upload(vault_name, upload_id, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/multipart-uploads/#{upload_id}" + + request( + :expects => 204, + :idempotent => true, + :headers => {}, + :method => :delete, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/complete_multipart_upload.rb b/lib/fog/aws/requests/glacier/complete_multipart_upload.rb new file mode 100644 index 000000000..450402470 --- /dev/null +++ b/lib/fog/aws/requests/glacier/complete_multipart_upload.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class Glacier + class Real + # Complete an upload + # + # ==== Parameters + # * name<~String> Name of the vault to upload to + # * upload_id<~String> The id of the upload to complete + # * total_size<~Integer> The total archive size + # * tree_hash<~String> the treehash for the archive + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-multipart-complete-upload.html + # + def complete_multipart_upload(vault_name, upload_id, total_size, tree_hash, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/multipart-uploads/#{upload_id}" + + headers = { + 'x-amz-archive-size' => total_size.to_s, + 'x-amz-sha256-tree-hash' => tree_hash + } + + request( + :expects => 201, + :idempotent => true, + :headers => headers, + :method => :post, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/create_archive.rb b/lib/fog/aws/requests/glacier/create_archive.rb new file mode 100644 index 000000000..1e06c8e7e --- /dev/null +++ b/lib/fog/aws/requests/glacier/create_archive.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class Glacier + class Real + # Upload an archive + # + # ==== Parameters + # * name<~String> Name of the vault to upload to + # * body<~String> The data to upload + # * options<~Hash> + # * description<~String> - The archive description + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-archive-post.html + # + def create_archive(vault_name, body, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/archives" + + headers = { + 'Content-Length' => body.bytesize.to_s, + 'x-amz-content-sha256' => Digest::SHA256.hexdigest(body), + 'x-amz-sha256-tree-hash' => Fog::AWS::Glacier::TreeHash.digest(body) + } + headers['x-amz-archive-description'] = Fog::AWS.escape(options['description']) if options['description'] + + request( + :expects => 201, + :headers => headers, + :method => :post, + :path => path, + :body => body + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/create_vault.rb b/lib/fog/aws/requests/glacier/create_vault.rb new file mode 100644 index 000000000..78f07e4f0 --- /dev/null +++ b/lib/fog/aws/requests/glacier/create_vault.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class Glacier + class Real + # This operation creates a new vault with the specified name. . + # + # ==== Parameters + # * name<~String> 1-255 characters. must be unique within a region for an Aws account + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-put.html + # + def create_vault(name,options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}" + request(options.merge({ + :expects => 201, + :idempotent => true, + :headers => {}, + :method => :put, + :path => path, + })) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/delete_archive.rb b/lib/fog/aws/requests/glacier/delete_archive.rb new file mode 100644 index 000000000..f65700653 --- /dev/null +++ b/lib/fog/aws/requests/glacier/delete_archive.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class Glacier + class Real + # Delete an archive + # + # ==== Parameters + # * name<~String> Name of the vault to delete + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-delete.html + # + def delete_archive(name,archive_id,options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}/archives/#{archive_id}" + request( + :expects => 204, + :idempotent => true, + :headers => {}, + :method => :delete, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/delete_vault.rb b/lib/fog/aws/requests/glacier/delete_vault.rb new file mode 100644 index 000000000..d4e4d61dc --- /dev/null +++ b/lib/fog/aws/requests/glacier/delete_vault.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class Glacier + class Real + # Delete a vault. Amazon Glacier will delete a vault only if there are no archives in the vault as per the last inventory + # and there have been no writes to the vault since the last inventory + # + # ==== Parameters + # * name<~String> Name of the vault to delete + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-delete.html + # + def delete_vault(name,options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}" + request( + :expects => 204, + :idempotent => true, + :headers => {}, + :method => :delete, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/delete_vault_notification_configuration.rb b/lib/fog/aws/requests/glacier/delete_vault_notification_configuration.rb new file mode 100644 index 000000000..0c7a4a4f6 --- /dev/null +++ b/lib/fog/aws/requests/glacier/delete_vault_notification_configuration.rb @@ -0,0 +1,31 @@ +module Fog + module AWS + class Glacier + class Real + # Delete vault's notification configuration + # + # ==== Parameters + # * name<~String> Name of the vault + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-notifications-delete.html + # + def delete_vault_notification_configuration(name,options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}/notification-configuration" + request( + :expects => 204, + :idempotent => true, + :headers => {}, + :method => :delete, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/describe_job.rb b/lib/fog/aws/requests/glacier/describe_job.rb new file mode 100644 index 000000000..2d06873f0 --- /dev/null +++ b/lib/fog/aws/requests/glacier/describe_job.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class Glacier + class Real + # Complete an upload + # + # ==== Parameters + # * name<~String> Name of the vault + # * job_id<~String> The id of the job + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-describe-job-get.html + # + def describe_job(vault_name, job_id, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/jobs/#{job_id}" + + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => :get, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/describe_vault.rb b/lib/fog/aws/requests/glacier/describe_vault.rb new file mode 100644 index 000000000..4c680cb06 --- /dev/null +++ b/lib/fog/aws/requests/glacier/describe_vault.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class Glacier + class Real + # This operation returns information about a vault + # + # ==== Parameters + # * name<~String> Vault name + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-get.html + # + def describe_vault(name,options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}" + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => :get, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/get_job_output.rb b/lib/fog/aws/requests/glacier/get_job_output.rb new file mode 100644 index 000000000..d5619a64a --- /dev/null +++ b/lib/fog/aws/requests/glacier/get_job_output.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class Glacier + class Real + # Get the output from a job + # + # ==== Parameters + # * name<~String> Name of the vault + # * job_id<~String> The id of the job + # * options<~Hash> + # * Range<~Range> The range to retrieve + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # * response_block<~Proc> Proc to use for streaming the response + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-job-output-get.html + # + def get_job_output(vault_name, job_id, options={}) + account_id = options.delete('account_id') || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/jobs/#{job_id}/output" + headers = {} + if range = options.delete('Range') + headers['Range'] = "bytes=#{range.begin}-#{range.end}" + end + request( + options.merge( + :expects => [200,206], + :idempotent => true, + :headers => headers, + :method => :get, + :path => path + )) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/get_vault_notification_configuration.rb b/lib/fog/aws/requests/glacier/get_vault_notification_configuration.rb new file mode 100644 index 000000000..817252867 --- /dev/null +++ b/lib/fog/aws/requests/glacier/get_vault_notification_configuration.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class Glacier + class Real + # Get a vault's notification configuration + # + # ==== Parameters + # * name<~String> Name of the vault + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-notifications-get.html + # + def get_vault_notification_configuration(name,options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}/notification-configuration" + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => :get, + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/initiate_job.rb b/lib/fog/aws/requests/glacier/initiate_job.rb new file mode 100644 index 000000000..b36f71992 --- /dev/null +++ b/lib/fog/aws/requests/glacier/initiate_job.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class Glacier + class Real + # This operation initates a multipart upload of an archive to a vault + # + # ==== Parameters + # * name<~String> The vault name + # * job_specification<~Hash> A specification of the job + # * Type<~String> The job type. Mandatory. Values: archive-retrieval, inventory-retrieval + # * Description<~String> The job description + # * ArchiveId<~String> The id of the archive to retrieve (only for Type==archive-retrieval) + # * Format<~String> The format to return (only for inventory retrieval). Values: CSV, JSON + # * SNSTopic ARN of a topic to publish to when the job is complete + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-initiate-job-post.html + # + def initiate_job(name, job_specification, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}/jobs" + + request({ + :expects => 202, + :headers => {}, + :method => 'POST', + :path => path, + :body => Fog::JSON.encode(job_specification) + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/initiate_multipart_upload.rb b/lib/fog/aws/requests/glacier/initiate_multipart_upload.rb new file mode 100644 index 000000000..35150fdb0 --- /dev/null +++ b/lib/fog/aws/requests/glacier/initiate_multipart_upload.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class Glacier + class Real + # This operation initates a multipart upload of an archive to a vault + # + # ==== Parameters + # * name<~String> The vault name + # * part_size<~Integer> The part size to use. Must be a power of 2 multiple of 1MB (1,2,4,8,16,...) + # * options<~Hash> + # * description<~String> - The archive description + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-multipart-initiate-upload.html + # + def initiate_multipart_upload(name, part_size, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}/multipart-uploads" + + headers = {'x-amz-part-size' => part_size.to_s} + headers['x-amz-archive-description'] = Fog::AWS.escape(options['description']) if options['description'] + request( + :expects => 201, + :headers => headers, + :method => 'POST', + :path => path + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/list_jobs.rb b/lib/fog/aws/requests/glacier/list_jobs.rb new file mode 100644 index 000000000..dda2afb54 --- /dev/null +++ b/lib/fog/aws/requests/glacier/list_jobs.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class Glacier + class Real + # lists in-progress and recently jobs for the specified vault + # + # ==== Parameters + # * name<~String> Name of the vault + # * options<~Hash> + # * completed<~Boolean>Specifies the state of the jobs to return. You can specify true or false + # * statuscode<~String> Filter returned jobs by status (InProgress, Succeeded, or Failed) + # * limit<~Integer> - The maximum number of items returned in the response. (default 1000) + # * marker<~String> - marker used for pagination + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # ==== See Also + #http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-jobs-get.html + # + def list_jobs(vault_name, options={}) + account_id = options.delete('account_id') || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/jobs" + + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => :get, + :path => path, + :query => options + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/list_multipart_uploads.rb b/lib/fog/aws/requests/glacier/list_multipart_uploads.rb new file mode 100644 index 000000000..77016cfe3 --- /dev/null +++ b/lib/fog/aws/requests/glacier/list_multipart_uploads.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class Glacier + class Real + # lists in-progress multipart uploads for the specified vault + # + # ==== Parameters + # * name<~String> Name of the vault + # * options<~Hash> + # * limit<~Integer> - The maximum number of items returned in the response. (default 1000) + # * marker<~String> - marker used for pagination + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-multipart-list-uploads.html + # + def list_multipart_uploads(vault_name, options={}) + account_id = options.delete('account_id') || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/multipart-uploads" + + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => :get, + :path => path, + :query => options + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/list_parts.rb b/lib/fog/aws/requests/glacier/list_parts.rb new file mode 100644 index 000000000..148a58e0f --- /dev/null +++ b/lib/fog/aws/requests/glacier/list_parts.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class Glacier + class Real + # lists the parts of an archive that have been uploaded in a specific multipart upload + # + # ==== Parameters + # * name<~String> Name of the vault + # * upload_id<~String> The id of the upload + # * options<~Hash> + # * limit<~Integer> - The maximum number of items returned in the response. (default 1000) + # * marker<~String> - marker used for pagination + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-multipart-list-parts.html + # + def list_parts(vault_name, upload_id, options={}) + account_id = options.delete('account_id') || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/multipart-uploads/#{Fog::AWS.escape(upload_id)}" + + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => :get, + :path => path, + :query => options + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/list_vaults.rb b/lib/fog/aws/requests/glacier/list_vaults.rb new file mode 100644 index 000000000..77aff047c --- /dev/null +++ b/lib/fog/aws/requests/glacier/list_vaults.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class Glacier + class Real + # This operation lists all vaults owned by the calling user’s account. + # + # ==== Parameters + # * options<~Hash> + # * limit<~Integer> - The maximum number of items returned in the response. (default 1000) + # * marker<~String> - marker used for pagination + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vaults-get.html + # + def list_vaults(options={}) + account_id = options.delete('account_id') || '-' + path = "/#{account_id}/vaults" + request( + :expects => 200, + :idempotent => true, + :headers => {}, + :method => 'GET', + :path => path, + :query => options + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/set_vault_notification_configuration.rb b/lib/fog/aws/requests/glacier/set_vault_notification_configuration.rb new file mode 100644 index 000000000..2475fd6cc --- /dev/null +++ b/lib/fog/aws/requests/glacier/set_vault_notification_configuration.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class Glacier + class Real + # Set a vault's notification configuration + # + # ==== Parameters + # * name<~String> Name of the vault + # * SnsTopic<~String> ARN of the topic to notify + # * events<~Array> Events you wish to receive. Valid events are ArchiveRetrievalCompleted, InventoryRetrievalCompleted + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-vault-notifications-put.html + # + def set_vault_notification_configuration(name,sns_topic, events, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(name)}/notification-configuration" + request( + :expects => 204, + :idempotent => true, + :headers => {}, + :method => :put, + :path => path, + :body => Fog::JSON.encode('SNSTopic' => sns_topic, 'Events' => events) + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/glacier/upload_part.rb b/lib/fog/aws/requests/glacier/upload_part.rb new file mode 100644 index 000000000..c68fefeb7 --- /dev/null +++ b/lib/fog/aws/requests/glacier/upload_part.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class Glacier + class Real + # Upload an archive + # + # ==== Parameters + # * name<~String> Name of the vault to upload to + # * uploadId<~String> Id of the upload + # * body<~String> The data to upload + # * offset<~Integer> The offset of the data within the archive + # * hash<~String> The tree hash for this part + # * options<~Hash> + # * account_id<~String> - The Aws account id. Defaults to the account owning the credentials making the request + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.amazonwebservices.com/amazonglacier/latest/dev/api-upload-part.html + # + def upload_part(vault_name, upload_id, body, offset, hash, options={}) + account_id = options['account_id'] || '-' + path = "/#{account_id}/vaults/#{Fog::AWS.escape(vault_name)}/multipart-uploads/#{Fog::AWS.escape(upload_id)}" + + headers = { + 'Content-Length' => body.bytesize.to_s, + 'Content-Range' => "bytes #{offset}-#{offset+body.bytesize-1}/*", + 'x-amz-content-sha256' => Digest::SHA256.hexdigest(body), + 'x-amz-sha256-tree-hash' => hash + } + + request( + :expects => 204, + :idempotent => true, + :headers => headers, + :method => :put, + :path => path, + :body => body + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/add_role_to_instance_profile.rb b/lib/fog/aws/requests/iam/add_role_to_instance_profile.rb new file mode 100644 index 000000000..7c3afd817 --- /dev/null +++ b/lib/fog/aws/requests/iam/add_role_to_instance_profile.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Add a role to an instance profile + # + # ==== Parameters + # * instance_profile_name<~String>: Name of the instance profile to update. + # * role_name<~String>:Name of the role to add. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_AddRoleToInstanceProfile.html + # + def add_role_to_instance_profile(role_name, instance_profile_name) + request( + 'Action' => 'AddRoleToInstanceProfile', + 'InstanceProfileName' => instance_profile_name, + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/add_user_to_group.rb b/lib/fog/aws/requests/iam/add_user_to_group.rb new file mode 100644 index 000000000..66a58f026 --- /dev/null +++ b/lib/fog/aws/requests/iam/add_user_to_group.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Add a user to a group + # + # ==== Parameters + # * group_name<~String>: name of the group + # * user_name<~String>: name of user to add + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_AddUserToGroup.html + # + def add_user_to_group(group_name, user_name) + request( + 'Action' => 'AddUserToGroup', + 'GroupName' => group_name, + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + + class Mock + def add_user_to_group(group_name, user_name) + if data[:groups].key? group_name + if data[:users].key? user_name + + unless data[:groups][group_name][:members].include?(user_name) + data[:groups][group_name][:members] << user_name + end + + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + end + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") + end + else + raise Fog::AWS::IAM::NotFound.new("The group with name #{group_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_access_key.rb b/lib/fog/aws/requests/iam/create_access_key.rb new file mode 100644 index 000000000..da5d35690 --- /dev/null +++ b/lib/fog/aws/requests/iam/create_access_key.rb @@ -0,0 +1,66 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/create_access_key' + + # Create a access keys for user (by default detects user from access credentials) + # + # ==== Parameters + # * options<~Hash>: + # * 'UserName'<~String> - name of the user to create (do not include path) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'AccessKey'<~Hash>: + # * 'AccessKeyId'<~String> - + # * 'UserName'<~String> - + # * 'SecretAccessKey'<~String> - + # * 'Status'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateAccessKey.html + # + def create_access_key(options = {}) + request({ + 'Action' => 'CreateAccessKey', + :parser => Fog::Parsers::AWS::IAM::CreateAccessKey.new + }.merge!(options)) + end + end + class Mock + def create_access_key(options) + #FIXME: Not 100% correct as Aws will use the signing credentials when there is no 'UserName' in the options hash + # Also doesn't raise an error when there are too many keys + if user = options['UserName'] + if data[:users].key? user + access_keys_data = data[:users][user][:access_keys] + else + raise Fog::AWS::IAM::NotFound.new('The user with name #{user_name} cannot be found.') + end + else + access_keys_data = data[:access_keys] + end + + key = { 'SecretAccessKey' => Fog::Mock.random_base64(40), + 'Status' => 'Active', + 'AccessKeyId' => Fog::AWS::Mock.key_id(20), + } + if user + key["UserName"] = user + end + + access_keys_data << key + + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'AccessKey' => key, + 'RequestId' => Fog::AWS::Mock.request_id } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_account_alias.rb b/lib/fog/aws/requests/iam/create_account_alias.rb new file mode 100644 index 000000000..7cd02e60c --- /dev/null +++ b/lib/fog/aws/requests/iam/create_account_alias.rb @@ -0,0 +1,17 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + def create_account_alias(account_alias) + request( + 'Action' => 'CreateAccountAlias', + 'AccountAlias' => account_alias, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_group.rb b/lib/fog/aws/requests/iam/create_group.rb new file mode 100644 index 000000000..3a3b5dc16 --- /dev/null +++ b/lib/fog/aws/requests/iam/create_group.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/create_group' + + # Create a new group + # + # ==== Parameters + # * group_name<~String>: name of the group to create (do not include path) + # * path<~String>: optional path to group, defaults to '/' + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Group'<~Hash>: + # * Arn<~String> - + # * GroupId<~String> - + # * GroupName<~String> - + # * Path<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateGroup.html + # + def create_group(group_name, path = '/') + request( + 'Action' => 'CreateGroup', + 'GroupName' => group_name, + 'Path' => path, + :parser => Fog::Parsers::AWS::IAM::CreateGroup.new + ) + end + end + + class Mock + def create_group(group_name, path = '/') + if data[:groups].key? group_name + raise Fog::AWS::IAM::EntityAlreadyExists.new("Group with name #{group_name} already exists.") + else + data[:groups][group_name][:path] = path + Excon::Response.new.tap do |response| + response.body = { 'Group' => { + 'GroupId' => (data[:groups][group_name][:group_id]).strip, + 'GroupName' => group_name, + 'Path' => path, + 'Arn' => (data[:groups][group_name][:arn]).strip }, + 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_instance_profile.rb b/lib/fog/aws/requests/iam/create_instance_profile.rb new file mode 100644 index 000000000..7c5b32341 --- /dev/null +++ b/lib/fog/aws/requests/iam/create_instance_profile.rb @@ -0,0 +1,45 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/instance_profile' + + # Create a new instance_profile + # + # ==== Parameters + # * instance_profile_name<~String>: name of the instance profile to create (do not include path) + # * path<~String>: optional path to group, defaults to '/' + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'InstanceProfile'<~Hash>: + # * Arn<~String> - + # * CreateDate<~Date> + # * InstanceProfileId<~String> - + # * InstanceProfileName<~String> - + # * Path<~String> - + # * Roles<~Array> - + # role<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateInstanceProfile.html + # + def create_instance_profile(instance_profile_name, path='/', options={}) + request({ + 'Action' => 'CreateInstanceProfile', + 'InstanceProfileName' => instance_profile_name, + 'Path' => path, + :parser => Fog::Parsers::AWS::IAM::InstanceProfile.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_login_profile.rb b/lib/fog/aws/requests/iam/create_login_profile.rb new file mode 100644 index 000000000..cca2cfc20 --- /dev/null +++ b/lib/fog/aws/requests/iam/create_login_profile.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/login_profile' + + # Creates a login profile for a user + # + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateLoginProfile.html + # ==== Parameters + # * user_name<~String> - Name of user to create a login profile for + # * password<~String> - The new password for this user + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'LoginProfile'<~Hash> + # * UserName<~String> + # * CreateDate + # * 'RequestId'<~String> - Id of the request + # + # + def create_login_profile(user_name, password) + request({ + 'Action' => 'CreateLoginProfile', + 'UserName' => user_name, + 'Password' => password, + :parser => Fog::Parsers::AWS::IAM::LoginProfile.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_role.rb b/lib/fog/aws/requests/iam/create_role.rb new file mode 100644 index 000000000..ccf8bab59 --- /dev/null +++ b/lib/fog/aws/requests/iam/create_role.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class IAM + # At the moment this is the only policy you can use + EC2_ASSUME_ROLE_POLICY = <<-JSON +{ + "Version":"2008-10-17", + "Statement":[ + { + "Effect":"Allow", + "Principal":{ + "Service":["ec2.amazonaws.com"] + }, + "Action":["sts:AssumeRole"] + } + ] +} + JSON + + class Real + require 'fog/aws/parsers/iam/single_role' + + # Creates a new role for your Aws account + # + # ==== Parameters + # * RoleName<~String>: name of the role to create + # * AssumeRolePolicyDocument<~String>: The policy that grants an entity permission to assume the role. + # * Path<~String>: This parameter is optional. If it is not included, it defaults to a slash (/). + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Role'<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateRole.html + # + def create_role(role_name, assume_role_policy_document, path = '/') + request( + 'Action' => 'CreateRole', + 'RoleName' => role_name, + 'AssumeRolePolicyDocument' => assume_role_policy_document, + 'Path' => path, + :parser => Fog::Parsers::AWS::IAM::SingleRole.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/create_user.rb b/lib/fog/aws/requests/iam/create_user.rb new file mode 100644 index 000000000..a4b6b949d --- /dev/null +++ b/lib/fog/aws/requests/iam/create_user.rb @@ -0,0 +1,59 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/create_user' + + # Create a new user + # + # ==== Parameters + # * user_name<~String>: name of the user to create (do not include path) + # * path<~String>: optional path to group, defaults to '/' + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'User'<~Hash>: + # * 'Arn'<~String> - + # * 'Path'<~String> - + # * 'UserId'<~String> - + # * 'UserName'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateUser.html + # + def create_user(user_name, path = '/') + request( + 'Action' => 'CreateUser', + 'UserName' => user_name, + 'Path' => path, + :parser => Fog::Parsers::AWS::IAM::CreateUser.new + ) + end + end + + class Mock + def create_user(user_name, path='/') + if data[:users].key? user_name + raise Fog::AWS::IAM::EntityAlreadyExists.new "User with name #{user_name} already exists." + else + data[:users][user_name][:path] = path + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'User' => { + "UserId" => data[:users][user_name][:user_id], + "Path" => path, + "UserName" => user_name, + "Arn" => (data[:users][user_name][:arn]).strip, + "CreateDate" => data[:users][user_name][:created_at] + }, + 'RequestId' => Fog::AWS::Mock.request_id + } + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_access_key.rb b/lib/fog/aws/requests/iam/delete_access_key.rb new file mode 100644 index 000000000..9beba0005 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_access_key.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Delete an access key + # + # ==== Parameters + # * access_key_id<~String> - Access key id to delete + # * options<~Hash>: + # * 'UserName'<~String> - name of the user to create (do not include path) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteAccessKey.html + # + def delete_access_key(access_key_id, options = {}) + request({ + 'AccessKeyId' => access_key_id, + 'Action' => 'DeleteAccessKey', + :parser => Fog::Parsers::AWS::IAM::Basic.new + }.merge!(options)) + end + end + + class Mock + def delete_access_key(access_key_id, options = {}) + user_name = options['UserName'] + if user_name && data[:users].key?(user_name) && data[:users][user_name][:access_keys].any? { |akey| akey['AccessKeyId'] == access_key_id } + data[:users][user_name][:access_keys].delete_if { |akey| akey['AccessKeyId'] == access_key_id } + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + else + raise Fog::AWS::IAM::NotFound.new("The Access Key with id #{access_key_id} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_account_alias.rb b/lib/fog/aws/requests/iam/delete_account_alias.rb new file mode 100644 index 000000000..a20c236ca --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_account_alias.rb @@ -0,0 +1,17 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + def delete_account_alias(account_alias) + request( + 'Action' => 'DeleteAccountAlias', + 'AccountAlias' => account_alias, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_account_password_policy.rb b/lib/fog/aws/requests/iam/delete_account_password_policy.rb new file mode 100644 index 000000000..57f3778e6 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_account_password_policy.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + # Add or update the account password policy + # + # ==== Parameters + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccountPasswordPolicy.html + # + def delete_account_password_policy + request({ + 'Action' => 'DeleteAccountPasswordPolicy', + :parser => Fog::Parsers::AWS::IAM::Basic.new + }) + end + end + + class Mock + def delete_account_password_policy + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_group.rb b/lib/fog/aws/requests/iam/delete_group.rb new file mode 100644 index 000000000..93ba12bbe --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_group.rb @@ -0,0 +1,48 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Delete a group + # + # ==== Parameters + # * group_name<~String>: name of the group to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteGroup.html + # + def delete_group(group_name) + request( + 'Action' => 'DeleteGroup', + 'GroupName' => group_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + + class Mock + def delete_group(group_name) + if data[:groups].key? group_name + if data[:groups][group_name][:members].empty? + data[:groups].delete group_name + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + end + else + raise Fog::AWS::IAM::Error.new("DeleteConflict => Cannot delete entity, must delete users in group first.") + end + else + raise Fog::AWS::IAM::NotFound.new("The group with name #{group_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_group_policy.rb b/lib/fog/aws/requests/iam/delete_group_policy.rb new file mode 100644 index 000000000..e57170f80 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_group_policy.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Remove a policy from a group + # + # ==== Parameters + # * group_name<~String>: name of the group + # * policy_name<~String>: name of policy document + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteGroupPolicy.html + # + def delete_group_policy(group_name, policy_name) + request( + 'Action' => 'DeleteGroupPolicy', + 'GroupName' => group_name, + 'PolicyName' => policy_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_instance_profile.rb b/lib/fog/aws/requests/iam/delete_instance_profile.rb new file mode 100644 index 000000000..4ccfc4f27 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_instance_profile.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Delete a instance_profile + # + # ==== Parameters + # * instance_profile_name<~String>: name of the instance_profile to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteInstanceProfile.html + # + def delete_instance_profile(instance_profile_name) + request( + 'Action' => 'DeleteInstanceProfile', + 'InstanceProfileName' => instance_profile_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_login_profile.rb b/lib/fog/aws/requests/iam/delete_login_profile.rb new file mode 100644 index 000000000..163f36ae4 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_login_profile.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Deletes a user's login profile + # + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteLoginProfile.html + # ==== Parameters + # * user_name<~String> - Name of user whose login profile you want to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # + def delete_login_profile(user_name) + request({ + 'Action' => 'DeleteLoginProfile', + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_role.rb b/lib/fog/aws/requests/iam/delete_role.rb new file mode 100644 index 000000000..02c2c548b --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_role.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Delete a role + # + # ==== Parameters + # * role_name<~String>: name of the role to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteRole.html + # + def delete_role(role_name) + request( + 'Action' => 'DeleteRole', + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_role_policy.rb b/lib/fog/aws/requests/iam/delete_role_policy.rb new file mode 100644 index 000000000..7293f1efb --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_role_policy.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Remove a policy from a role + # + # ==== Parameters + # * role_name<~String>: name of the role + # * policy_name<~String>: name of policy document + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteRolePolicy.html + # + def delete_role_policy(role_name, policy_name) + request( + 'Action' => 'DeleteRolePolicy', + 'PolicyName' => policy_name, + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_server_certificate.rb b/lib/fog/aws/requests/iam/delete_server_certificate.rb new file mode 100644 index 000000000..d9a5d0253 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_server_certificate.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Deletes the specified server certificate. + # + # ==== Parameters + # * server_certificate_name<~String>: The name of the server certificate you want to delete. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteServerCertificate.html + # + def delete_server_certificate(server_certificate_name) + request({ + 'Action' => 'DeleteServerCertificate', + 'ServerCertificateName' => server_certificate_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }) + end + end + + class Mock + def delete_server_certificate(server_certificate_name) + response = Excon::Response.new + response.status = 200 + response.body = { + 'RequestId' => Fog::AWS::Mock.request_id + } + + unless self.data[:server_certificates].delete(server_certificate_name) + raise Fog::AWS::IAM::NotFound.new("The Server Certificate with name #{server_certificate_name} cannot be found.") + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_signing_certificate.rb b/lib/fog/aws/requests/iam/delete_signing_certificate.rb new file mode 100644 index 000000000..b13726f19 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_signing_certificate.rb @@ -0,0 +1,31 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Upload signing certificate for user (by default detects user from access credentials) + # + # ==== Parameters + # * options<~Hash>: + # * 'UserName'<~String> - name of the user to upload certificate for (do not include path) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_DeleteSigningCertificate.html + # + def delete_signing_certificate(certificate_id, options = {}) + request({ + 'Action' => 'DeleteSigningCertificate', + 'CertificateId' => certificate_id, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_user.rb b/lib/fog/aws/requests/iam/delete_user.rb new file mode 100644 index 000000000..833520b2e --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_user.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Delete a user + # + # ==== Parameters + # * user_name<~String>: name of the user to delete + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteUser.html + # + def delete_user(user_name) + request( + 'Action' => 'DeleteUser', + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + + class Mock + def delete_user(user_name) + if data[:users].key? user_name + data[:users].delete user_name + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/delete_user_policy.rb b/lib/fog/aws/requests/iam/delete_user_policy.rb new file mode 100644 index 000000000..a12ba93e6 --- /dev/null +++ b/lib/fog/aws/requests/iam/delete_user_policy.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Remove a policy from a user + # + # ==== Parameters + # * user_name<~String>: name of the user + # * policy_name<~String>: name of policy document + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_DeleteUserPolicy.html + # + def delete_user_policy(user_name, policy_name) + request( + 'Action' => 'DeleteUserPolicy', + 'PolicyName' => policy_name, + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + + class Mock + def delete_user_policy(user_name, policy_name) + if data[:users].key?(user_name) && data[:users][user_name][:policies].key?(policy_name) + data[:users][user_name][:policies].delete policy_name + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + else + raise Fog::AWS::IAM::NotFound.new("The user policy with name #{policy_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_account_password_policy.rb b/lib/fog/aws/requests/iam/get_account_password_policy.rb new file mode 100644 index 000000000..c900a9d66 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_account_password_policy.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + # Add or update the account password policy + # + # ==== Parameters + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccountPasswordPolicy.html + # + def get_account_password_policy() + request({ + 'Action' => 'DeleteAccountPasswordPolicy', + :parser => Fog::Parsers::AWS::IAM::Basic.new + }) + end + end + + class Mock + def get_account_password_policy() + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_account_summary.rb b/lib/fog/aws/requests/iam/get_account_summary.rb new file mode 100644 index 000000000..773abd266 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_account_summary.rb @@ -0,0 +1,75 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/get_account_summary' + + # Retrieve account level information about account entity usage and IAM quotas + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Summary'<~Hash>: + # * 'AccessKeysPerUserQuota'<~Integer> - Maximum number of access keys that can be created per user + # * 'AccountMFAEnabled'<~Integer> - 1 if the root account has an MFA device assigned to it, 0 otherwise + # * 'AssumeRolePolicySizeQuota'<~Integer> - Maximum allowed size for assume role policy documents (in kilobytes) + # * 'GroupPolicySizeQuota'<~Integer> - Maximum allowed size for Group policy documents (in kilobytes) + # * 'Groups'<~Integer> - Number of Groups for the Aws account + # * 'GroupsPerUserQuota'<~Integer> - Maximum number of groups a user can belong to + # * 'GroupsQuota'<~Integer> - Maximum groups allowed for the Aws account + # * 'InstanceProfiles'<~Integer> - Number of instance profiles for the Aws account + # * 'InstanceProfilesQuota'<~Integer> - Maximum instance profiles allowed for the Aws account + # * 'MFADevices'<~Integer> - Number of MFA devices, either assigned or unassigned + # * 'MFADevicesInUse'<~Integer> - Number of MFA devices that have been assigned to an IAM user or to the root account + # * 'Providers'<~Integer> - + # * 'RolePolicySizeQuota'<~Integer> - Maximum allowed size for role policy documents (in kilobytes) + # * 'Roles'<~Integer> - Number of roles for the Aws account + # * 'RolesQuota'<~Integer> - Maximum roles allowed for the Aws account + # * 'ServerCertificates'<~Integer> - Number of server certificates for the Aws account + # * 'ServerCertificatesQuota'<~Integer> - Maximum server certificates allowed for the Aws account + # * 'SigningCertificatesPerUserQuota'<~Integer> - Maximum number of X509 certificates allowed for a user + # * 'UserPolicySizeQuota'<~Integer> - Maximum allowed size for user policy documents (in kilobytes) + # * 'Users'<~Integer> - Number of users for the Aws account + # * 'UsersQuota'<~Integer> - Maximum users allowed for the Aws account + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateAccessKey.html + # + def get_account_summary + request( + 'Action' => 'GetAccountSummary', + :parser => Fog::Parsers::AWS::IAM::GetAccountSummary.new + ) + end + end + + class Mock + def get_account_summary + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { + 'Summary' => { + 'AccessKeysPerUserQuota' => 2, + 'AccountMFAEnabled' => 0, + 'GroupPolicySizeQuota' => 10240, + 'Groups' => 31, + 'GroupsPerUserQuota' => 10, + 'GroupsQuota' => 50, + 'MFADevices' => 20, + 'MFADevicesInUse' => 10, + 'ServerCertificates' => 5, + 'ServerCertificatesQuota' => 10, + 'SigningCertificatesPerUserQuota' => 2, + 'UserPolicySizeQuota' => 10240, + 'Users' => 35, + 'UsersQuota' => 150, + }, + 'RequestId' => Fog::AWS::Mock.request_id + } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_group.rb b/lib/fog/aws/requests/iam/get_group.rb new file mode 100644 index 000000000..c62a8c79a --- /dev/null +++ b/lib/fog/aws/requests/iam/get_group.rb @@ -0,0 +1,60 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/get_group' + + # Get Group + # + # ==== Parameters + # * 'GroupName'<~String>: Name of the Group + # * options<~Hash>: + # * 'Marker'<~String>: Use this only when paginating results, and only in a subsequent request after you've received a response where the results are truncated. Set it to the value of the Marker element in the response you just received. + # * 'MaxItems'<~String>: Use this only when paginating results to indicate the maximum number of User names you want in the response. If there are additional User names beyond the maximum you specify, the IsTruncated response element is true. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Group'<~Hash> - Group + # * 'Path'<~String> + # * 'GroupName'<~String> + # * 'Arn'<~String> + # * 'Users'<~Hash>? - List of users belonging to the group. + # * 'User'<~Hash> - User + # * Arn<~String> - + # * UserId<~String> - + # * UserName<~String> - + # * Path<~String> - + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_GetGroup.html + # + def get_group(group_name, options = {}) + request({ + 'Action' => 'GetGroup', + 'GroupName' => group_name, + :parser => Fog::Parsers::AWS::IAM::GetGroup.new + }.merge!(options)) + end + end + class Mock + def get_group(group_name, options = {}) + raise Fog::AWS::IAM::NotFound.new( + "The user with name #{group_name} cannot be found." + ) unless self.data[:groups].key?(group_name) + Excon::Response.new.tap do |response| + response.body = { 'Group' => { + 'GroupId' => data[:groups][group_name][:group_id], + 'Path' => data[:groups][group_name][:path], + 'GroupName' => group_name, + 'Arn' => (data[:groups][group_name][:arn]).strip + }, + 'Users' => data[:groups][group_name][:members].map { |user| get_user(user).body['User'] }, + 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_group_policy.rb b/lib/fog/aws/requests/iam/get_group_policy.rb new file mode 100644 index 000000000..4dec0a150 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_group_policy.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/get_group_policy' + + # Get Group Policy + # + # ==== Parameters + # * 'PolicyName'<~String>: Name of the policy to get + # * 'GroupName'<~String>: Name of the Group who the policy is associated with. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * PolicyDocument<~String> The policy document. + # * PolicyName<~String> The name of the policy. + # * GroupName<~String> The Group the policy is associated with. + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetGroupPolicy.html + # + def get_group_policy(policy_name, group_name) + request({ + 'Action' => 'GetGroupPolicy', + 'PolicyName' => policy_name, + 'GroupName' => group_name, + :parser => Fog::Parsers::AWS::IAM::GetGroupPolicy.new + }) + end + end + class Mock + def get_group_policy(policy_name, group_name) + raise Fog::AWS::IAM::NotFound.new("The group with name #{group_name} cannot be found.") unless self.data[:groups].key?(group_name) + raise Fog::AWS::IAM::NotFound.new("The policy with name #{policy_name} cannot be found.") unless self.data[:groups][group_name][:policies].key?(policy_name) + Excon::Response.new.tap do |response| + response.body = { 'Policy' => { + 'PolicyName' => policy_name, + 'GroupName' => group_name, + 'PolicyDocument' => data[:groups][group_name][:policies][policy_name] + }, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id + } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_instance_profile.rb b/lib/fog/aws/requests/iam/get_instance_profile.rb new file mode 100644 index 000000000..ba33a0bb9 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_instance_profile.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/instance_profile' + + # Retrieves information about an instance profile + # + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetInstanceProfile.html + # ==== Parameters + # * instance_profile_name<~String> - Name of instance_profile to retrieve the information for + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'InstanceProfile'<~Hash>: + # * Arn<~String> - + # * CreateDate<~Date> + # * InstanceProfileId<~String> - + # * InstanceProfileName<~String> - + # * Path<~String> - + # * Roles<~Array> - + # role<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'RequestId'<~String> - Id of the request + def get_instance_profile(instance_profile_name) + request({ + 'Action' => 'GetInstanceProfile', + 'InstanceProfileName' => instance_profile_name, + :parser => Fog::Parsers::AWS::IAM::InstanceProfile.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_login_profile.rb b/lib/fog/aws/requests/iam/get_login_profile.rb new file mode 100644 index 000000000..6f9470925 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_login_profile.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/login_profile' + + # Retrieves the login profile for a user + # + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_CreateLoginProfile.html + # ==== Parameters + # * user_name<~String> - Name of user to retrieve the login profile for + # * password<~String> - The new password for this user + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'LoginProfile'<~Hash> + # * UserName<~String> + # * CreateDate + # * 'RequestId'<~String> - Id of the request + # + # + def get_login_profile(user_name) + request({ + 'Action' => 'GetLoginProfile', + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::LoginProfile.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_role.rb b/lib/fog/aws/requests/iam/get_role.rb new file mode 100644 index 000000000..c60f8999d --- /dev/null +++ b/lib/fog/aws/requests/iam/get_role.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/single_role' + + # Get the specified role + # + # ==== Parameters + # role_name<~String> + + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * Role<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetRole.html + # + def get_role(role_name) + request( + 'Action' => 'GetRole', + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::SingleRole.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_role_policy.rb b/lib/fog/aws/requests/iam/get_role_policy.rb new file mode 100644 index 000000000..cab6e83b7 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_role_policy.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/get_role_policy' + + # Get Role Policy + # + # ==== Parameters + # * 'PolicyName'<~String>: Name of the policy to get + # * 'RoleName'<~String>: Name of the Role who the policy is associated with. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * PolicyDocument<~String> The policy document. + # * PolicyName<~String> The name of the policy. + # * RoleName<~String> The Role the policy is associated with. + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetRolePolicy.html + # + def get_role_policy(role_name, policy_name) + request({ + 'Action' => 'GetRolePolicy', + 'PolicyName' => policy_name, + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::GetRolePolicy.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_server_certificate.rb b/lib/fog/aws/requests/iam/get_server_certificate.rb new file mode 100644 index 000000000..c9c21d8fd --- /dev/null +++ b/lib/fog/aws/requests/iam/get_server_certificate.rb @@ -0,0 +1,45 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/upload_server_certificate' + + # Gets the specified server certificate. + # + # ==== Parameters + # * server_certificate_name<~String>: The name of the server certificate you want to get. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetServerCertificate.html + # + def get_server_certificate(name) + request({ + 'Action' => 'GetServerCertificate', + 'ServerCertificateName' => name, + :parser => Fog::Parsers::AWS::IAM::UploadServerCertificate.new + }) + end + end + + class Mock + def get_server_certificate(name) + raise Fog::AWS::IAM::NotFound unless certificate = self.data[:server_certificates][name] + + response = Excon::Response.new + response.status = 200 + response.body = { + 'Certificate' => certificate, + 'RequestId' => Fog::AWS::Mock.request_id + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_user.rb b/lib/fog/aws/requests/iam/get_user.rb new file mode 100644 index 000000000..4fe7d6a9c --- /dev/null +++ b/lib/fog/aws/requests/iam/get_user.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/get_user' + + # Get User + # + # ==== Parameters + # * username + # * options<~Hash>: + # * 'UserName'<~String>: Name of the User. Defaults to current user + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'User'<~Hash> - User + # * Arn<~String> - + # * UserId<~String> - + # * UserName<~String> - + # * Path<~String> - + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_Getuser.html + # + def get_user(username, options = {}) + request({ + 'Action' => 'GetUser', + 'UserName' => username, + :parser => Fog::Parsers::AWS::IAM::GetUser.new + }.merge!(options)) + end + end + + class Mock + def get_user(user, options = {}) + raise Fog::AWS::IAM::NotFound.new( + "The user with name #{user} cannot be found." + ) unless self.data[:users].key?(user) + Excon::Response.new.tap do |response| + response.body = {'User' => { + 'UserId' => data[:users][user][:user_id], + 'Path' => data[:users][user][:path], + 'UserName' => user, + 'Arn' => (data[:users][user][:arn]).strip, + 'CreateDate' => data[:users][user][:created_at] + }, + 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/get_user_policy.rb b/lib/fog/aws/requests/iam/get_user_policy.rb new file mode 100644 index 000000000..d5a953be3 --- /dev/null +++ b/lib/fog/aws/requests/iam/get_user_policy.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/get_user_policy' + + # Get User Policy + # + # ==== Parameters + # * 'PolicyName'<~String>: Name of the policy to get + # * 'UserName'<~String>: Name of the User who the policy is associated with. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * PolicyDocument<~String> The policy document. + # * PolicyName<~String> The name of the policy. + # * UserName<~String> The User the policy is associated with. + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetUserPolicy.html + # + def get_user_policy(policy_name, user_name) + request({ + 'Action' => 'GetUserPolicy', + 'PolicyName' => policy_name, + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::GetUserPolicy.new + }) + end + end + class Mock + def get_user_policy(policy_name, user_name) + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") unless self.data[:users].key?(user_name) + raise Fog::AWS::IAM::NotFound.new("The policy with name #{policy_name} cannot be found.") unless self.data[:users][user_name][:policies].key?(policy_name) + Excon::Response.new.tap do |response| + response.body = { 'Policy' => { + 'PolicyName' => policy_name, + 'UserName' => user_name, + 'PolicyDocument' => data[:users][user_name][:policies][policy_name] + }, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id + } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_access_keys.rb b/lib/fog/aws/requests/iam/list_access_keys.rb new file mode 100644 index 000000000..6c42cfc2c --- /dev/null +++ b/lib/fog/aws/requests/iam/list_access_keys.rb @@ -0,0 +1,62 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_access_keys' + + # List access_keys + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String> - used to paginate subsequent requests + # * 'MaxItems'<~Integer> - limit results to this number per page + # * 'UserName'<~String> - optional: username to lookup access keys for, defaults to current user + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'AccessKeys'<~Array> - Matching access keys + # * access_key<~Hash>: + # * AccessKeyId<~String> - + # * Status<~String> - + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListAccessKeys.html + # + def list_access_keys(options = {}) + request({ + 'Action' => 'ListAccessKeys', + :parser => Fog::Parsers::AWS::IAM::ListAccessKeys.new + }.merge!(options)) + end + end + + class Mock + def list_access_keys(options = {}) + #FIXME: Doesn't do anything with options, aside from UserName + if user = options['UserName'] + if data[:users].key? user + access_keys_data = data[:users][user][:access_keys] + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user} cannot be found.") + end + else + access_keys_data = data[:access_keys] + end + + Excon::Response.new.tap do |response| + response.body = { 'AccessKeys' => access_keys_data.map do |akey| + {'Status' => akey['Status'], 'AccessKeyId' => akey['AccessKeyId']} + end, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_account_aliases.rb b/lib/fog/aws/requests/iam/list_account_aliases.rb new file mode 100644 index 000000000..9197896c6 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_account_aliases.rb @@ -0,0 +1,16 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_account_aliases' + + def list_account_aliases(options = {}) + request({ + 'Action' => 'ListAccountAliases', + :parser => Fog::Parsers::AWS::IAM::ListAccountAliases.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_group_policies.rb b/lib/fog/aws/requests/iam/list_group_policies.rb new file mode 100644 index 000000000..f83adc924 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_group_policies.rb @@ -0,0 +1,37 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_policies' + + # List policies for a group + # + # ==== Parameters + # * group_name<~String> - Name of group to list policies for + # * options<~Hash>: Optional + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'PathPrefix'<~String>: prefix for filtering results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'PolicyNames'<~Array> - Matching policy names + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListGroupPolicies.html + # + def list_group_policies(group_name, options = {}) + request({ + 'Action' => 'ListGroupPolicies', + 'GroupName' => group_name, + :parser => Fog::Parsers::AWS::IAM::ListPolicies.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_groups.rb b/lib/fog/aws/requests/iam/list_groups.rb new file mode 100644 index 000000000..8084c3862 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_groups.rb @@ -0,0 +1,57 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_groups' + + # List groups + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'PathPrefix'<~String>: prefix for filtering results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Groups'<~Array> - Matching groups + # * group<~Hash>: + # * Arn<~String> - + # * GroupId<~String> - + # * GroupName<~String> - + # * Path<~String> - + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListGroups.html + # + def list_groups(options = {}) + request({ + 'Action' => 'ListGroups', + :parser => Fog::Parsers::AWS::IAM::ListGroups.new + }.merge!(options)) + end + end + + class Mock + def list_groups(options = {} ) + #FIXME: Doesn't observe options + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'Groups' => data[:groups].map do |name, group| + { 'GroupId' => group[:group_id], + 'GroupName' => name, + 'Path' => group[:path], + 'Arn' => (group[:arn]).strip } + end, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_groups_for_user.rb b/lib/fog/aws/requests/iam/list_groups_for_user.rb new file mode 100644 index 000000000..d5b72a565 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_groups_for_user.rb @@ -0,0 +1,65 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_groups_for_user' + + # List groups_for_user + # + # ==== Parameters + # * user_name<~String> - the username you want to look up group membership for + # * options<~Hash>: + # * 'Marker'<~String> - used to paginate subsequent requests + # * 'MaxItems'<~Integer> - limit results to this number per page + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'GroupsForUser'<~Array> - Groups for a user + # * group_for_user<~Hash>: + # * 'Arn' - + # * 'GroupId' - + # * 'GroupName' - + # * 'Path' - + # * 'IsTruncated'<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListGroupsForUser.html + # + def list_groups_for_user(user_name, options = {}) + request({ + 'Action' => 'ListGroupsForUser', + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::ListGroupsForUser.new + }.merge!(options)) + end + end + + class Mock + def list_groups_for_user(user_name, options = {}) + #FIXME: Does not consider options + if data[:users].key? user_name + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'GroupsForUser' => data[:groups].select do |name, group| + group[:members].include? user_name + end.map do |name, group| + { 'GroupId' => group[:group_id], + 'GroupName' => name, + 'Path' => group[:path], + 'Arn' => (group[:arn]).strip } + end, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id + } + end + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_instance_profiles.rb b/lib/fog/aws/requests/iam/list_instance_profiles.rb new file mode 100644 index 000000000..95d876cfc --- /dev/null +++ b/lib/fog/aws/requests/iam/list_instance_profiles.rb @@ -0,0 +1,48 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_instance_profiles' + + # Lists instance profiles + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'PathPrefix'<~String>: prefix for filtering results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'InstanceProfiles'<~Array>: + # * instance_profile <~Hash>: + # * Arn<~String> - + # * CreateDate<~Date> + # * InstanceProfileId<~String> - + # * InstanceProfileName<~String> - + # * Path<~String> - + # * Roles<~Array> - + # role<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListInstanceProfiles.html + # + def list_instance_profiles(options={}) + request({ + 'Action' => 'ListInstanceProfiles', + :parser => Fog::Parsers::AWS::IAM::ListInstanceProfiles.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_instance_profiles_for_role.rb b/lib/fog/aws/requests/iam/list_instance_profiles_for_role.rb new file mode 100644 index 000000000..45a8af69b --- /dev/null +++ b/lib/fog/aws/requests/iam/list_instance_profiles_for_role.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_instance_profiles' + + # Lists the instance profiles that have the specified associated role + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'RoleName'<~String>: The name of the role to list instance profiles for. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'InstanceProfiles'<~Array>: + # * instance_profile <~Hash>: + # * Arn<~String> - + # * CreateDate<~Date> + # * InstanceProfileId<~String> - + # * InstanceProfileName<~String> - + # * Path<~String> - + # * Roles<~Array> - + # role<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListInstanceProfilesForRole.html + # + def list_instance_profiles_for_role(role_name,options={}) + request({ + 'Action' => 'ListInstanceProfilesForRole', + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::ListInstanceProfiles.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_mfa_devices.rb b/lib/fog/aws/requests/iam/list_mfa_devices.rb new file mode 100644 index 000000000..99e648918 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_mfa_devices.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_mfa_devices' + + # List MFA Devices + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String> - used to paginate subsequent requests + # * 'MaxItems'<~Integer> - limit results to this number per page + # * 'UserName'<~String> - optional: username to lookup mfa devices for, defaults to current user + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'MFADevices'<~Array> - Matching MFA devices + # * mfa_device<~Hash>: + # * EnableDate - The date when the MFA device was enabled for the user + # * SerialNumber<~String> - The serial number that uniquely identifies the MFA device + # * UserName<~String> - The user with whom the MFA device is associated + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.aws.amazon.com/IAM/latest/APIReference/API_ListMFADevices.html + # + def list_mfa_devices(options = {}) + request({ + 'Action' => 'ListMFADevices', + :parser => Fog::Parsers::AWS::IAM::ListMFADevices.new + }.merge!(options)) + end + end + + class Mock + def list_mfa_devices(options = {}) + #FIXME: Doesn't observe options + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'MFADevices' => data[:devices].map do |device| + { 'EnableDate' => device[:enable_date], + 'SerialNumber' => device[:serial_number], + 'UserName' => device[:user_name] } + end, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_role_policies.rb b/lib/fog/aws/requests/iam/list_role_policies.rb new file mode 100644 index 000000000..26962dc23 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_role_policies.rb @@ -0,0 +1,37 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_policies' + + # Lists the names of policies associated with a role + # + # ==== Parameters + # * role_name<~String>: the role to list policies for + # * options<~Hash>: + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'PolicyNames'<~Array>: + # * policy_name <~String> + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListRoleProfiles.html + # + def list_role_policies(role_name,options={}) + request({ + 'Action' => 'ListRolePolicies', + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::ListPolicies.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_roles.rb b/lib/fog/aws/requests/iam/list_roles.rb new file mode 100644 index 000000000..18267c1be --- /dev/null +++ b/lib/fog/aws/requests/iam/list_roles.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_roles' + + # Lists roles + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'PathPrefix'<~String>: prefix for filtering results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * Roles<~Array> - + # role<~Hash>: + # * 'Arn'<~String> - + # * 'AssumeRolePolicyDocument'<~String< + # * 'Path'<~String> - + # * 'RoleId'<~String> - + # * 'RoleName'<~String> - + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListRoles.html + # + def list_roles(options={}) + request({ + 'Action' => 'ListRoles', + :parser => Fog::Parsers::AWS::IAM::ListRoles.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_server_certificates.rb b/lib/fog/aws/requests/iam/list_server_certificates.rb new file mode 100644 index 000000000..11a0eab83 --- /dev/null +++ b/lib/fog/aws/requests/iam/list_server_certificates.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_server_certificates' + + # List server certificates + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String> - The marker from the previous result (for pagination) + # * 'MaxItems'<~String> - The maximum number of server certificates you want in the response + # * 'PathPrefix'<~String> - The path prefix for filtering the results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Certificates'<~Array> - Matching server certificates + # * server_certificate<~Hash>: + # * Arn<~String> - + # * Path<~String> - + # * ServerCertificateId<~String> - + # * ServerCertificateName<~String> - + # * UploadDate<~Time> - + # * 'IsTruncated'<~Boolean> - Whether or not the results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_ListServerCertificates.html + # + def list_server_certificates(options = {}) + request({ + 'Action' => 'ListServerCertificates', + :parser => Fog::Parsers::AWS::IAM::ListServerCertificates.new + }.merge!(options)) + end + end + + class Mock + def list_server_certificates(options = {}) + certificates = self.data[:server_certificates].values + certificates = certificates.select { |certificate| certificate['Path'] =~ Regexp.new("^#{options['PathPrefix']}") } if options['PathPrefix'] + response = Excon::Response.new + response.status = 200 + response.body = { + 'Certificates' => certificates + } + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_signing_certificates.rb b/lib/fog/aws/requests/iam/list_signing_certificates.rb new file mode 100644 index 000000000..cb519713d --- /dev/null +++ b/lib/fog/aws/requests/iam/list_signing_certificates.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_signing_certificates' + + # List signing certificates for user (by default detects user from access credentials) + # + # ==== Parameters + # * options<~Hash>: + # * 'UserName'<~String> - name of the user to list certificates for (do not include path) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'SigningCertificates'<~Array> - Matching signing certificates + # * signing_certificate<~Hash>: + # * CertificateId<~String> - + # * Status<~String> - + # * 'IsTruncated'<~Boolean> - Whether or not the results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_ListSigningCertificates.html + # + def list_signing_certificates(options = {}) + request({ + 'Action' => 'ListSigningCertificates', + :parser => Fog::Parsers::AWS::IAM::ListSigningCertificates.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_user_policies.rb b/lib/fog/aws/requests/iam/list_user_policies.rb new file mode 100644 index 000000000..261543c1e --- /dev/null +++ b/lib/fog/aws/requests/iam/list_user_policies.rb @@ -0,0 +1,53 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_policies' + + # List policies for a user + # + # ==== Parameters + # * user_name<~String> - Name of user to list policies for + # * options<~Hash>: Optional + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'PathPrefix'<~String>: prefix for filtering results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'PolicyNames'<~Array> - Matching policy names + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListUserPolicies.html + # + def list_user_policies(user_name, options = {}) + request({ + 'Action' => 'ListUserPolicies', + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::ListPolicies.new + }.merge!(options)) + end + end + + class Mock + def list_user_policies(user_name, options = {}) + #FIXME: doesn't use options atm + if data[:users].key? user_name + Excon::Response.new.tap do |response| + response.body = { 'PolicyNames' => data[:users][user_name][:policies].keys, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/list_users.rb b/lib/fog/aws/requests/iam/list_users.rb new file mode 100644 index 000000000..ae3cb7f4f --- /dev/null +++ b/lib/fog/aws/requests/iam/list_users.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/list_users' + + # List users + # + # ==== Parameters + # * options<~Hash>: + # * 'Marker'<~String>: used to paginate subsequent requests + # * 'MaxItems'<~Integer>: limit results to this number per page + # * 'PathPrefix'<~String>: prefix for filtering results + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Users'<~Array> - Matching groups + # * user<~Hash>: + # * Arn<~String> - + # * Path<~String> - + # * UserId<~String> - + # * UserName<~String> - + # * 'IsTruncated<~Boolean> - Whether or not results were truncated + # * 'Marker'<~String> - appears when IsTruncated is true as the next marker to use + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListUsers.html + # + def list_users(options = {}) + request({ + 'Action' => 'ListUsers', + :parser => Fog::Parsers::AWS::IAM::ListUsers.new + }.merge!(options)) + end + end + + class Mock + def list_users(options = {}) + #FIXME: none of the options are currently supported + Excon::Response.new.tap do |response| + response.body = {'Users' => data[:users].map do |user, data| + { 'UserId' => data[:user_id], + 'Path' => data[:path], + 'UserName' => user, + 'Arn' => (data[:arn]).strip, + 'CreateDate' => data[:created_at]} + end, + 'IsTruncated' => false, + 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/put_group_policy.rb b/lib/fog/aws/requests/iam/put_group_policy.rb new file mode 100644 index 000000000..adebc168a --- /dev/null +++ b/lib/fog/aws/requests/iam/put_group_policy.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Add or update a policy for a group + # + # ==== Parameters + # * group_name<~String>: name of the group + # * policy_name<~String>: name of policy document + # * policy_document<~Hash>: policy document, see: http://docs.amazonwebservices.com/IAM/latest/UserGuide/PoliciesOverview.html + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_PutGroupPolicy.html + # + def put_group_policy(group_name, policy_name, policy_document) + request( + 'Action' => 'PutGroupPolicy', + 'GroupName' => group_name, + 'PolicyName' => policy_name, + 'PolicyDocument' => Fog::JSON.encode(policy_document), + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + class Mock + #FIXME: You can't actually use the credentials for anything elsewhere in Fog + #FIXME: Doesn't do any validation on the policy + def put_group_policy(group_name, policy_name, policy_document) + if data[:groups].key? group_name + data[:groups][group_name][:policies][policy_name] = policy_document + + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + else + raise Fog::AWS::IAM::NotFound.new("The group with name #{group_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/put_role_policy.rb b/lib/fog/aws/requests/iam/put_role_policy.rb new file mode 100644 index 000000000..f6924ef34 --- /dev/null +++ b/lib/fog/aws/requests/iam/put_role_policy.rb @@ -0,0 +1,34 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Add or update a policy for a role + # + # ==== Parameters + # * role_name<~String>: name of the role + # * policy_name<~String>: name of policy document + # * policy_document<~Hash>: policy document, see: http://docs.amazonwebservices.com/IAM/latest/UserGuide/PoliciesOverview.html + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_PutRolePolicy.html + # + def put_role_policy(role_name, policy_name, policy_document) + request( + 'Action' => 'PutRolePolicy', + 'RoleName' => role_name, + 'PolicyName' => policy_name, + 'PolicyDocument' => Fog::JSON.encode(policy_document), + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/put_user_policy.rb b/lib/fog/aws/requests/iam/put_user_policy.rb new file mode 100644 index 000000000..4ca089c3e --- /dev/null +++ b/lib/fog/aws/requests/iam/put_user_policy.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Add or update a policy for a user + # + # ==== Parameters + # * user_name<~String>: name of the user + # * policy_name<~String>: name of policy document + # * policy_document<~Hash>: policy document, see: http://docs.amazonwebservices.com/IAM/latest/UserGuide/PoliciesOverview.html + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_PutUserPolicy.html + # + def put_user_policy(user_name, policy_name, policy_document) + request( + 'Action' => 'PutUserPolicy', + 'PolicyName' => policy_name, + 'PolicyDocument' => Fog::JSON.encode(policy_document), + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + + class Mock + #FIXME: You can't actually use the credentials for anything elsewhere in Fog + #FIXME: Doesn't do any validation on the policy + def put_user_policy(user_name, policy_name, policy_document) + if data[:users].key? user_name + data[:users][user_name][:policies][policy_name] = policy_document + + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/remove_role_from_instance_profile.rb b/lib/fog/aws/requests/iam/remove_role_from_instance_profile.rb new file mode 100644 index 000000000..e2380203e --- /dev/null +++ b/lib/fog/aws/requests/iam/remove_role_from_instance_profile.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # removes a role from an instance profile + # + # Make sure you do not have any Amazon EC2 instances running with the role you are about to remove from the instance profile. + # ==== Parameters + # * instance_profile_name<~String>: Name of the instance profile to update. + # * role_name<~String>:Name of the role to remove. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_RemoveRoleFromInstanceProfile.html + # + def remove_role_from_instance_profile(role_name, instance_profile_name) + request( + 'Action' => 'RemoveRoleFromInstanceProfile', + 'InstanceProfileName' => instance_profile_name, + 'RoleName' => role_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/remove_user_from_group.rb b/lib/fog/aws/requests/iam/remove_user_from_group.rb new file mode 100644 index 000000000..f7b89ca84 --- /dev/null +++ b/lib/fog/aws/requests/iam/remove_user_from_group.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Remove a user from a group + # + # ==== Parameters + # * group_name<~String>: name of the group + # * user_name<~String>: name of user to remove + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_RemoveUserFromGroup.html + # + def remove_user_from_group(group_name, user_name) + request( + 'Action' => 'RemoveUserFromGroup', + 'GroupName' => group_name, + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + ) + end + end + + class Mock + def remove_user_from_group(group_name, user_name) + if data[:groups].key? group_name + if data[:users].key? user_name + data[:groups][group_name][:members].delete_if { |item| item == user_name } + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + end + else + raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.") + end + else + raise Fog::AWS::IAM::NotFound.new("The group with name #{group_name} cannot be found.") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_access_key.rb b/lib/fog/aws/requests/iam/update_access_key.rb new file mode 100644 index 000000000..4e84cba04 --- /dev/null +++ b/lib/fog/aws/requests/iam/update_access_key.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Update an access key for a user + # + # ==== Parameters + # * access_key_id<~String> - Access key id to delete + # * status<~String> - status of keys in ['Active', 'Inactive'] + # * options<~Hash>: + # * 'UserName'<~String> - name of the user to create (do not include path) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_UpdateAccessKey.html + # + def update_access_key(access_key_id, status, options = {}) + request({ + 'AccessKeyId' => access_key_id, + 'Action' => 'UpdateAccessKey', + 'Status' => status, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }.merge!(options)) + end + end + + class Mock + def update_access_key(access_key_id, status, options = {}) + if user = options['UserName'] + if data[:users].key? user + access_keys_data = data[:users][user][:access_keys] + else + raise Fog::AWS::IAM::NotFound.new('The user with name #{user_name} cannot be found.') + end + else + access_keys_data = data[:access_keys] + end + key = access_keys_data.find{|k| k["AccessKeyId"] == access_key_id} + key["Status"] = status + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { 'AccessKey' => key, + 'RequestId' => Fog::AWS::Mock.request_id } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_account_password_policy.rb b/lib/fog/aws/requests/iam/update_account_password_policy.rb new file mode 100644 index 000000000..d46c71fd0 --- /dev/null +++ b/lib/fog/aws/requests/iam/update_account_password_policy.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + # Add or update the account password policy + # + # ==== Parameters + # * MinimumPasswordLength<~integer> Minimum length to require for IAM user passwords. + # * MaxPasswordAge<~integer> The number of days that an IAM user password is valid. + # * PasswordReusePrevention<~integer> Specifies the number of previous passwords that IAM users are prevented from reusing. + # * RequireSymbols<~boolean> Specifies whether to require symbols for IAM user passwords. + # * RequireNumbers<~boolean> Specifies whether to require numbers for IAM user passwords. + # * RequireUppercaseCharacters<~boolean> Specifies whether to require uppercase characters for IAM user passwords. + # * RequireLowercaseCharacters<~boolean> Specifies whether to require lowercase characters for IAM user passwords. + # * AllowUsersToChangePassword<~boolean> Specifies whether IAM users are allowed to change their own password. + # * HardExpiry<~boolean> Specifies whether IAM users are prevented from setting a new password after their password has expired. + # * ExpirePasswords<~boolean> Specifies whether IAM users are required to change their password after a specified number of days. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccountPasswordPolicy.html + # + def update_account_password_policy(minimum_password_length, max_password_age, password_reuse_prevention,require_symbols,require_numbers,require_uppercase_characters, require_lowercase_characters,allow_users_to_change_password, hard_expiry, expire_passwords) + request({ + 'Action' => 'UpdateAccountPasswordPolicy', + 'MinimumPasswordLength' => minimum_password_length, + 'MaxPasswordAge' => max_password_age, + 'PasswordReusePrevention' => password_reuse_prevention, + 'RequireSymbols' => require_symbols, + 'RequireNumbers' => require_numbers, + 'RequireUppercaseCharacters' => require_uppercase_characters, + 'RequireLowercaseCharacters' => require_lowercase_characters, + 'AllowUsersToChangePassword' => allow_users_to_change_password, + 'HardExpiry' => hard_expiry, + 'ExpirePasswords' => expire_passwords, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }) + end + end + + class Mock + def update_account_password_policy(minimum_password_length, max_password_age, password_reuse_prevention,require_symbols,require_numbers,require_uppercase_characters, require_lowercase_characters,allow_users_to_change_password, hard_expiry, expire_passwords) + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_group.rb b/lib/fog/aws/requests/iam/update_group.rb new file mode 100644 index 000000000..79dd6b8c8 --- /dev/null +++ b/lib/fog/aws/requests/iam/update_group.rb @@ -0,0 +1,37 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/update_group' + + # Update a Group + # + # ==== Parameters + # * group_name<~String> - Required. Name of the Group to update. If you're changing the name of the Group, this is the original Group name. + # * options<~Hash>: + # * new_path<~String> - New path for the Group. Include this parameter only if you're changing the Group's path. + # * new_group_name<~String> - New name for the Group. Include this parameter only if you're changing the Group's name. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # * 'Group'<~Hash> - Changed Group info + # * 'Arn'<~String> - + # * 'Path'<~String> - + # * 'GroupId'<~String> - + # * 'GroupName'<~String> - + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UpdateGroup.html + # + def update_group(group_name, options = {}) + request({ + 'Action' => 'UpdateGroup', + 'GroupName' => group_name, + :parser => Fog::Parsers::AWS::IAM::UpdateGroup.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_login_profile.rb b/lib/fog/aws/requests/iam/update_login_profile.rb new file mode 100644 index 000000000..40a3ab436 --- /dev/null +++ b/lib/fog/aws/requests/iam/update_login_profile.rb @@ -0,0 +1,31 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/basic' + + # Updates a login profile for a user + # + # http://docs.amazonwebservices.com/IAM/latest/APIReference/API_UpdateLoginProfile.html + # ==== Parameters + # * user_name<~String> - Name of user to change the login profile for + # * password<~String> - The new password for this user + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # + def update_login_profile(user_name, password) + request({ + 'Action' => 'UpdateLoginProfile', + 'UserName' => user_name, + 'Password' => password, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_server_certificate.rb b/lib/fog/aws/requests/iam/update_server_certificate.rb new file mode 100644 index 000000000..762199eef --- /dev/null +++ b/lib/fog/aws/requests/iam/update_server_certificate.rb @@ -0,0 +1,63 @@ +module Fog + module AWS + class IAM + class Real + # Updates the name and/or the path of the specified server certificate. + # + # ==== Parameters + # * server_certificate_name<~String> - The name of the server + # certificate that you want to update. + # * options<~Hash>: + # * 'NewPath'<~String> - The new path for the server certificate. + # Include this only if you are updating the server certificate's + # path. + # * 'NewServerCertificateName'<~String> - The new name for the server + # certificate. Include this only if you are updating the server + # certificate's name. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UpdateServerCertificate.html + # + def update_server_certificate(server_certificate_name, options = {}) + request({ + 'Action' => 'UpdateServerCertificate', + 'ServerCertificateName' => server_certificate_name, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }.merge!(options)) + end + end + + class Mock + def update_server_certificate(server_certificate_name, options = {}) + new_server_certificate_name = options['NewServerCertificateName'] + if self.data[:server_certificates][new_server_certificate_name] + raise Fog::AWS::IAM::EntityAlreadyExists.new("The Server Certificate with name #{server_certificate_name} already exists.") + end + unless certificate = self.data[:server_certificates].delete(server_certificate_name) + raise Fog::AWS::IAM::NotFound.new("The Server Certificate with name #{server_certificate_name} cannot be found.") + end + + if new_server_certificate_name + certificate['ServerCertificateName'] = new_server_certificate_name + end + + if new_path = options['NewPath'] + certificate['Path'] = new_path + end + + self.data[:server_certificates][certificate['ServerCertificateName']] = certificate + + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_signing_certificate.rb b/lib/fog/aws/requests/iam/update_signing_certificate.rb new file mode 100644 index 000000000..fe011ce87 --- /dev/null +++ b/lib/fog/aws/requests/iam/update_signing_certificate.rb @@ -0,0 +1,31 @@ +module Fog + module AWS + class IAM + class Real + # Update a Signing Certificate + # + # ==== Parameters + # * certificate_id<~String> - Required. ID of the Certificate to update. + # * status<~String> - Required. Active/Inactive + # * options<~Hash>: + # * user_name<~String> - Name of the user the signing certificate belongs to. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UpdateSigningCertificate.html + # + def update_signing_certificate(certificate_id, status, options = {}) + request({ + 'Action' => 'UpdateSigningCertificate', + 'CertificateId' => certificate_id, + 'Status' => status, + :parser => Fog::Parsers::AWS::IAM::Basic.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/update_user.rb b/lib/fog/aws/requests/iam/update_user.rb new file mode 100644 index 000000000..b73d1912f --- /dev/null +++ b/lib/fog/aws/requests/iam/update_user.rb @@ -0,0 +1,37 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/update_user' + + # Update a user + # + # ==== Parameters + # * user_name<~String> - Required. Name of the User to update. If you're changing the name of the User, this is the original User name. + # * options<~Hash>: + # * new_path<~String> - New path for the User. Include this parameter only if you're changing the User's path. + # * new_user_name<~String> - New name for the User. Include this parameter only if you're changing the User's name. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'RequestId'<~String> - Id of the request + # * 'User'<~Hash> - Changed user info + # * 'Arn'<~String> - + # * 'Path'<~String> - + # * 'UserId'<~String> - + # * 'UserName'<~String> - + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UpdateUser.html + # + def update_user(user_name, options = {}) + request({ + 'Action' => 'UpdateUser', + 'UserName' => user_name, + :parser => Fog::Parsers::AWS::IAM::UpdateUser.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/upload_server_certificate.rb b/lib/fog/aws/requests/iam/upload_server_certificate.rb new file mode 100644 index 000000000..cd8ee3ecd --- /dev/null +++ b/lib/fog/aws/requests/iam/upload_server_certificate.rb @@ -0,0 +1,95 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/upload_server_certificate' + + # Uploads a server certificate entity for the Aws Account. + # Includes a public key certificate, a private key, and an optional certificate chain, which should all be PEM-encoded. + # + # ==== Parameters + # * certificate<~Hash>: The contents of the public key certificate in PEM-encoded format. + # * private_key<~Hash>: The contents of the private key in PEM-encoded format. + # * name<~Hash>: The name for the server certificate. Do not include the path in this value. + # * options<~Hash>: + # * 'CertificateChain'<~String> - The contents of the certificate chain. Typically a concatenation of the PEM-encoded public key certificates of the chain. + # * 'Path'<~String> - The path for the server certificate. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Certificate'<~Hash>: + # * 'Arn'<~String> - + # * 'Path'<~String> - + # * 'ServerCertificateId'<~String> - + # * 'ServerCertificateName'<~String> - + # * 'UploadDate'<~Time> + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UploadServerCertificate.html + # + def upload_server_certificate(certificate, private_key, name, options = {}) + request({ + 'Action' => 'UploadServerCertificate', + 'CertificateBody' => certificate, + 'PrivateKey' => private_key, + 'ServerCertificateName' => name, + :parser => Fog::Parsers::AWS::IAM::UploadServerCertificate.new + }.merge!(options)) + end + end + + class Mock + def upload_server_certificate(certificate, private_key, name, options = {}) + if certificate.nil? || certificate.empty? || private_key.nil? || private_key.empty? + raise Fog::AWS::IAM::ValidationError.new + end + response = Excon::Response.new + + # Validate cert and key + begin + # must be an RSA private key + raise OpenSSL::PKey::RSAError unless private_key =~ /BEGIN RSA PRIVATE KEY/ + + cert = OpenSSL::X509::Certificate.new(certificate) + chain = OpenSSL::X509::Certificate.new(options['CertificateChain']) if options['CertificateChain'] + key = OpenSSL::PKey::RSA.new(private_key) + rescue OpenSSL::X509::CertificateError, OpenSSL::PKey::RSAError => e + message = if e.is_a?(OpenSSL::X509::CertificateError) + "Invalid Public Key Certificate." + else + "Invalid Private Key." + end + raise Fog::AWS::IAM::MalformedCertificate.new(message) + end + + unless cert.check_private_key(key) + raise Fog::AWS::IAM::KeyPairMismatch.new + end + + if self.data[:server_certificates][name] + raise Fog::AWS::IAM::EntityAlreadyExists.new("The Server Certificate with name #{name} already exists.") + else + response.status = 200 + path = options['Path'] || "/" + data = { + 'Arn' => Fog::AWS::Mock.arn('iam', self.data[:owner_id], "server-certificate/#{name}"), + 'Path' => path, + 'ServerCertificateId' => Fog::AWS::IAM::Mock.server_certificate_id, + 'ServerCertificateName' => name, + 'UploadDate' => Time.now + } + self.data[:server_certificates][name] = data + response.body = { + 'Certificate' => data, + 'RequestId' => Fog::AWS::Mock.request_id + } + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/iam/upload_signing_certificate.rb b/lib/fog/aws/requests/iam/upload_signing_certificate.rb new file mode 100644 index 000000000..c77c875f4 --- /dev/null +++ b/lib/fog/aws/requests/iam/upload_signing_certificate.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class IAM + class Real + require 'fog/aws/parsers/iam/upload_signing_certificate' + + # Upload signing certificate for user (by default detects user from access credentials) + # + # ==== Parameters + # * options<~Hash>: + # * 'UserName'<~String> - name of the user to upload certificate for (do not include path) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Certificate'<~Hash>: + # * 'CertificateId'<~String> - + # * 'UserName'<~String> - + # * 'CertificateBody'<~String> - + # * 'Status'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.amazonwebservices.com/IAM/latest/APIReference/index.html?API_UploadSigningCertificate.html + # + def upload_signing_certificate(certificate, options = {}) + request({ + 'Action' => 'UploadSigningCertificate', + 'CertificateBody' => certificate, + :parser => Fog::Parsers::AWS::IAM::UploadSigningCertificate.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/add_tags_to_resource.rb b/lib/fog/aws/requests/rds/add_tags_to_resource.rb new file mode 100644 index 000000000..4ee57ddc9 --- /dev/null +++ b/lib/fog/aws/requests/rds/add_tags_to_resource.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class RDS + class Real + # adds tags to a database instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_AddTagsToResource.html + # ==== Parameters + # * rds_id <~String> - name of the RDS instance whose tags are to be retrieved + # * tags <~Hash> A Hash of (String) key-value pairs + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def add_tags_to_resource(rds_id, tags) + keys = tags.keys.sort + values = keys.map {|key| tags[key]} + request({ + 'Action' => 'AddTagsToResource', + 'ResourceName' => "arn:aws:rds:#{@region}:#{owner_id}:db:#{rds_id}", + :parser => Fog::Parsers::AWS::RDS::Base.new, + }.merge(Fog::AWS.indexed_param('Tags.member.%d.Key', keys)). + merge(Fog::AWS.indexed_param('Tags.member.%d.Value', values))) + end + end + + class Mock + def add_tags_to_resource(rds_id, tags) + response = Excon::Response.new + if server = self.data[:servers][rds_id] + self.data[:tags][rds_id].merge! tags + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id } + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{rds_id} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/authorize_db_security_group_ingress.rb b/lib/fog/aws/requests/rds/authorize_db_security_group_ingress.rb new file mode 100644 index 000000000..5c3135144 --- /dev/null +++ b/lib/fog/aws/requests/rds/authorize_db_security_group_ingress.rb @@ -0,0 +1,65 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/authorize_db_security_group_ingress' + + # authorizes a db security group ingress + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_AuthorizeDBSecurityGroupIngress.html + # ==== Parameters + # * CIDRIP <~String> - The IP range to authorize + # * DBSecurityGroupName <~String> - The name for the DB Security Group. + # * EC2SecurityGroupName <~String> - Name of the EC2 Security Group to authorize. + # * EC2SecurityGroupOwnerId <~String> - Aws Account Number of the owner of the security group specified in the EC2SecurityGroupName parameter. The Aws Access Key ID is not an acceptable value. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def authorize_db_security_group_ingress(name, opts={}) + unless opts.key?('CIDRIP') || (opts.key?('EC2SecurityGroupName') && opts.key?('EC2SecurityGroupOwnerId')) + raise ArgumentError, 'Must specify CIDRIP, or both EC2SecurityGroupName and EC2SecurityGroupOwnerId' + end + + request({ + 'Action' => 'AuthorizeDBSecurityGroupIngress', + :parser => Fog::Parsers::AWS::RDS::AuthorizeDBSecurityGroupIngress.new, + 'DBSecurityGroupName' => name + }.merge(opts)) + end + end + + class Mock + def authorize_db_security_group_ingress(name, opts = {}) + unless opts.key?('CIDRIP') || (opts.key?('EC2SecurityGroupName') && opts.key?('EC2SecurityGroupOwnerId')) + raise ArgumentError, 'Must specify CIDRIP, or both EC2SecurityGroupName and EC2SecurityGroupOwnerId' + end + + response = Excon::Response.new + + if sec_group = self.data[:security_groups][name] + if opts.key?('CIDRIP') + if sec_group['IPRanges'].find{|h| h['CIDRIP'] == opts['CIDRIP']} + raise Fog::AWS::RDS::AuthorizationAlreadyExists.new("AuthorizationAlreadyExists => #{opts['CIDRIP']} is alreay defined") + end + sec_group['IPRanges'] << opts.merge({"Status" => 'authorizing'}) + else + if sec_group['EC2SecurityGroups'].find{|h| h['EC2SecurityGroupName'] == opts['EC2SecurityGroupName']} + raise Fog::AWS::RDS::AuthorizationAlreadyExists.new("AuthorizationAlreadyExists => #{opts['EC2SecurityGroupName']} is alreay defined") + end + sec_group['EC2SecurityGroups'] << opts.merge({"Status" => 'authorizing'}) + end + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + 'AuthorizeDBSecurityGroupIngressResult' => { + 'DBSecurityGroup' => sec_group + } + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBSecurityGroupNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_db_instance.rb b/lib/fog/aws/requests/rds/create_db_instance.rb new file mode 100644 index 000000000..797fbb8b8 --- /dev/null +++ b/lib/fog/aws/requests/rds/create_db_instance.rb @@ -0,0 +1,132 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_db_instance' + + # Create a db instance + # + # @param DBInstanceIdentifier [String] name of the db instance to modify + # @param AllocatedStorage [Integer] Storage space, in GB + # @param AutoMinorVersionUpgrade [Boolean] Indicates that minor version upgrades will be applied automatically to the DB Instance during the maintenance window + # @param AvailabilityZone [String] The availability zone to create the instance in + # @param BackupRetentionPeriod [Integer] 0-8 The number of days to retain automated backups. + # @param DBInstanceClass [String] The new compute and memory capacity of the DB Instance + # @param DBName [String] The name of the database to create when the DB Instance is created + # @param DBParameterGroupName [String] The name of the DB Parameter Group to apply to this DB Instance + # @param DBSecurityGroups [Array] A list of DB Security Groups to authorize on this DB Instance + # @param Engine [String] The name of the database engine to be used for this instance. + # @param EngineVersion [String] The version number of the database engine to use. + # @param Iops [Integer] IOPS rate + # @param MasterUsername [String] The db master user + # @param MasterUserPassword [String] The new password for the DB Instance master user + # @param MultiAZ [Boolean] Specifies if the DB Instance is a Multi-AZ deployment + # @param Port [Integer] The port number on which the database accepts connections. + # @param PreferredBackupWindow [String] The daily time range during which automated backups are created if automated backups are enabled + # @param PreferredMaintenanceWindow [String] The weekly time range (in UTC) during which system maintenance can occur, which may result in an outage + # @param DBSubnetGroupName [String] The name, if any, of the VPC subnet for this RDS instance + # @param PubliclyAcccesible [Boolean] Whether an RDS instance inside of the VPC subnet should have a public-facing endpoint + # @param VpcSecurityGroups [Array] A list of VPC Security Groups to authorize on this DB instance + # @param StorageType [string] Specifies storage type to be associated with the DB Instance. Valid values: standard | gp2 | io1 + # + # @return [Excon::Response]: + # * body [Hash]: + # + # @see http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html + def create_db_instance(db_name, options={}) + if security_groups = options.delete('DBSecurityGroups') + options.merge!(Fog::AWS.indexed_param('DBSecurityGroups.member.%d', [*security_groups])) + end + + if vpc_security_groups = options.delete('VpcSecurityGroups') + options.merge!(Fog::AWS.indexed_param('VpcSecurityGroupIds.member.%d', [*vpc_security_groups])) + end + + request({ + 'Action' => 'CreateDBInstance', + 'DBInstanceIdentifier' => db_name, + :parser => Fog::Parsers::AWS::RDS::CreateDBInstance.new, + }.merge(options)) + end + end + + class Mock + def create_db_instance(db_name, options={}) + response = Excon::Response.new + if self.data[:servers] and self.data[:servers][db_name] + # I don't know how to raise an exception that contains the excon data + #response.status = 400 + #response.body = { + # 'Code' => 'DBInstanceAlreadyExists', + # 'Message' => "DB Instance already exists" + #} + #return response + raise Fog::AWS::RDS::IdentifierTaken.new("DBInstanceAlreadyExists #{response.body.to_s}") + end + + # These are the required parameters according to the API + required_params = %w{AllocatedStorage DBInstanceClass Engine MasterUserPassword MasterUsername } + required_params.each do |key| + unless options.key?(key) and options[key] and !options[key].to_s.empty? + #response.status = 400 + #response.body = { + # 'Code' => 'MissingParameter', + # 'Message' => "The request must contain the parameter #{key}" + #} + #return response + raise Fog::AWS::RDS::NotFound.new("The request must contain the parameter #{key}") + end + end + + data = + { + "DBInstanceIdentifier"=> db_name, + "DBName" => options["DBName"], + "InstanceCreateTime" => nil, + "AutoMinorVersionUpgrade"=>true, + "Endpoint"=>{}, + "ReadReplicaDBInstanceIdentifiers"=>[], + "PreferredMaintenanceWindow"=>"mon:04:30-mon:05:00", + "Engine"=> options["Engine"], + "EngineVersion"=> options["EngineVersion"] || "5.5.12", + "PendingModifiedValues"=>{"MasterUserPassword"=>"****"}, # This clears when is available + "MultiAZ"=> !!options['MultiAZ'], + "MasterUsername"=> options["MasterUsername"], + "DBInstanceClass"=> options["DBInstanceClass"], + "DBInstanceStatus"=>"creating", + "BackupRetentionPeriod"=> options["BackupRetentionPeriod"] || 1, + "AllocatedStorage"=> options["AllocatedStorage"], + "Iops" => options["Iops"], + "DBParameterGroups"=> # I think groups should be in the self.data method + [{"DBParameterGroupName"=>"default.mysql5.5", + "ParameterApplyStatus"=>"in-sync"}], + "DBSecurityGroups"=> + [{"Status"=>"active", + "DBSecurityGroupName"=>"default"}], + "LicenseModel"=>"general-public-license", + "PreferredBackupWindow"=>"08:00-08:30", +# "ReadReplicaSourceDBInstanceIdentifier" => nil, +# "LatestRestorableTime" => nil, + "AvailabilityZone" => options["AvailabilityZone"], + "DBSubnetGroupName" => options["DBSubnetGroupName"], + "PubliclyAccessible" => options["PubliclyAccessible"], + "VpcSecurityGroups" => options["VpcSecurityGroups"], + "StorageType" => options["StorageType"], + } + + self.data[:servers][db_name] = data + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CreateDBInstanceResult"=> {"DBInstance"=> data} + } + response.status = 200 + # This values aren't showed at creating time but at available time + self.data[:servers][db_name]["InstanceCreateTime"] = Time.now + self.data[:tags] ||= {} + self.data[:tags][db_name] = {} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_db_instance_read_replica.rb b/lib/fog/aws/requests/rds/create_db_instance_read_replica.rb new file mode 100644 index 000000000..098fe8ff8 --- /dev/null +++ b/lib/fog/aws/requests/rds/create_db_instance_read_replica.rb @@ -0,0 +1,77 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_db_instance_read_replica' + + # create a read replica db instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_CreateDBInstanceReadReplica.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - name of the db instance to create + # * SourceDBInstanceIdentifier <~String> - name of the db instance that will be the source. Must have backup retention on + # * AutoMinorVersionUpgrade <~Boolean> Indicates that minor version upgrades will be applied automatically to the DB Instance during the maintenance window + # * AvailabilityZone <~String> The availability zone to create the instance in + # * DBInstanceClass <~String> The new compute and memory capacity of the DB Instance + # * Port <~Integer> The port number on which the database accepts connections. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_db_instance_read_replica(instance_identifier, source_identifier, options={}) + request({ + 'Action' => 'CreateDBInstanceReadReplica', + 'DBInstanceIdentifier' => instance_identifier, + 'SourceDBInstanceIdentifier' => source_identifier, + :parser => Fog::Parsers::AWS::RDS::CreateDBInstanceReadReplica.new, + }.merge(options)) + end + end + + class Mock + def create_db_instance_read_replica(instance_identifier, source_identifier, options={}) + # TODO: throw error when instance_identifier already exists, + # or source_identifier doesn't exist + + source = self.data[:servers][source_identifier] + data = { + 'AllocatedStorage' => source['AllocatedStorage'], + 'AutoMinorVersionUpgrade' => options.key?('AutoMinorVersionUpgrade') ? options['AutoMinorVersionUpgrade'] : true, + 'AvailabilityZone' => options['AvailabilityZone'], + 'DBInstanceClass' => options['DBInstanceClass'] || 'db.m1.small', + 'DBInstanceIdentifier' => instance_identifier, + 'DBInstanceStatus' => 'creating', + 'DBName' => source['DBName'], + 'DBParameterGroups' => source['DBParameterGroups'], + 'DBSecurityGroups' => source['DBSecurityGroups'], + 'Endpoint' => {}, + 'Engine' => source['Engine'], + 'EngineVersion' => options['EngineVersion'] || '5.5.12', + 'InstanceCreateTime' => nil, + 'Iops' => source['Iops'], + 'LatestRestorableTime' => nil, + 'LicenseModel' => 'general-public-license', + 'MasterUsername' => source['MasterUsername'], + 'MultiAZ' => false, + 'PendingModifiedValues' => {}, + 'PreferredBackupWindow'=> '08:00-08:30', + 'PreferredMaintenanceWindow'=> "mon:04:30-mon:05:00", + 'ReadReplicaDBInstanceIdentifiers'=> [], + 'ReadReplicaSourceDBInstanceIdentifier'=> source_identifier + } + self.data[:servers][instance_identifier] = data + self.data[:servers][source_identifier]['ReadReplicaDBInstanceIdentifiers'] << instance_identifier + + response = Excon::Response.new + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CreateDBInstanceReadReplicaResult"=> {"DBInstance"=> data} + } + response.status = 200 + # This values aren't showed at creating time but at available time + self.data[:servers][instance_identifier]["InstanceCreateTime"] = Time.now + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_db_parameter_group.rb b/lib/fog/aws/requests/rds/create_db_parameter_group.rb new file mode 100644 index 000000000..6b1aa47ac --- /dev/null +++ b/lib/fog/aws/requests/rds/create_db_parameter_group.rb @@ -0,0 +1,53 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_db_parameter_group' + + # create a database parameter group + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_CreateDBParameterGroup.html + # ==== Parameters + # * DBParameterGroupName <~String> - name of the parameter group + # * DBParameterGroupFamily <~String> - The DB parameter group family name. Current valid values: MySQL5.1 | MySQL5.5 + # * Description <~String> - The description for the DB Parameter Grou + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_db_parameter_group(group_name, group_family, description) + request({ + 'Action' => 'CreateDBParameterGroup', + 'DBParameterGroupName' => group_name, + 'DBParameterGroupFamily' => group_family, + 'Description' => description, + + :parser => Fog::Parsers::AWS::RDS::CreateDbParameterGroup.new + }) + end + end + + class Mock + def create_db_parameter_group(group_name, group_family, description) + response = Excon::Response.new + if self.data[:parameter_groups] and self.data[:parameter_groups][group_name] + raise Fog::AWS::RDS::IdentifierTaken.new("Parameter group #{group_name} already exists") + end + + data = { + 'DBParameterGroupName' => group_name, + 'DBParameterGroupFamily' => group_family.downcase, + 'Description' => description + } + self.data[:parameter_groups][group_name] = data + + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CreateDBParameterGroupResult"=> {"DBParameterGroup"=> data} + } + response.status = 200 + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_db_security_group.rb b/lib/fog/aws/requests/rds/create_db_security_group.rb new file mode 100644 index 000000000..93835a9a4 --- /dev/null +++ b/lib/fog/aws/requests/rds/create_db_security_group.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_db_security_group' + + # creates a db security group + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_CreateDBSecurityGroup.html + # ==== Parameters + # * DBSecurityGroupDescription <~String> - The description for the DB Security Group + # * DBSecurityGroupName <~String> - The name for the DB Security Group. This value is stored as a lowercase string. Must contain no more than 255 alphanumeric characters or hyphens. Must not be "Default". + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_db_security_group(name, description = name) + request({ + 'Action' => 'CreateDBSecurityGroup', + 'DBSecurityGroupName' => name, + 'DBSecurityGroupDescription' => description, + :parser => Fog::Parsers::AWS::RDS::CreateDBSecurityGroup.new + }) + end + end + + class Mock + def create_db_security_group(name, description = name) + response = Excon::Response.new + if self.data[:security_groups] and self.data[:security_groups][name] + raise Fog::AWS::RDS::IdentifierTaken.new("DBInstanceAlreadyExists => The security group '#{name}' already exists") + end + + data = { + 'DBSecurityGroupName' => name, + 'DBSecurityGroupDescription' => description, + 'EC2SecurityGroups' => [], + 'IPRanges' => [], + 'OwnerId' => '0123456789' + } + self.data[:security_groups][name] = data + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + 'CreateDBSecurityGroupResult' => { 'DBSecurityGroup' => data } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_db_snapshot.rb b/lib/fog/aws/requests/rds/create_db_snapshot.rb new file mode 100644 index 000000000..41316bd05 --- /dev/null +++ b/lib/fog/aws/requests/rds/create_db_snapshot.rb @@ -0,0 +1,68 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_db_snapshot' + + # creates a db snapshot + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_CreateDBSnapshot.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - ID of instance to create snapshot for + # * DBSnapshotIdentifier <~String> - The identifier for the DB Snapshot. 1-255 alphanumeric or hyphen characters. Must start with a letter + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_db_snapshot(identifier, name) + request({ + 'Action' => 'CreateDBSnapshot', + 'DBInstanceIdentifier' => identifier, + 'DBSnapshotIdentifier' => name, + :parser => Fog::Parsers::AWS::RDS::CreateDBSnapshot.new + }) + end + end + + class Mock + def create_db_snapshot(identifier, name) + response = Excon::Response.new + if data[:snapshots][name] + raise Fog::AWS::RDS::IndentifierTaken.new + end + + server_data = data[:servers][identifier] + unless server_data + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end + + # TODO: raise an error if the server isn't in 'available' state + + snapshot_data = { + 'Status' => 'creating', + 'SnapshotType' => 'manual', + 'DBInstanceIdentifier' => identifier, + 'DBSnapshotIdentifier' => name, + 'InstanceCreateTime' => Time.now + } + # Copy attributes from server + %w(Engine EngineVersion AvailabilityZone AllocatedStorage Iops MasterUsername InstanceCreateTime).each do |key| + snapshot_data[key] = server_data[key] + end + snapshot_data['Port'] = server_data['Endpoint']['Port'] + + self.data[:snapshots][name] = snapshot_data + + # TODO: put the server in 'modifying' state + + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CreateDBSnapshotResult"=> {"DBSnapshot"=> snapshot_data.dup} + } + response.status = 200 + # SnapshotCreateTime is not part of the response. + self.data[:snapshots][name]['SnapshotCreateTime'] = Time.now + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_db_subnet_group.rb b/lib/fog/aws/requests/rds/create_db_subnet_group.rb new file mode 100644 index 000000000..0c4d37c1f --- /dev/null +++ b/lib/fog/aws/requests/rds/create_db_subnet_group.rb @@ -0,0 +1,61 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_db_subnet_group' + + # Creates a db subnet group + # http://docs.amazonwebservices.com/AmazonRDS/2012-01-15/APIReference/API_CreateDBSubnetGroup.html + # ==== Parameters + # * DBSubnetGroupName <~String> - The name for the DB Subnet Group. This value is stored as a lowercase string. Must contain no more than 255 alphanumeric characters or hyphens. Must not be "Default". + # * SubnetIds <~Array> - The EC2 Subnet IDs for the DB Subnet Group. + # * DBSubnetGroupDescription <~String> - The description for the DB Subnet Group + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def create_db_subnet_group(name, subnet_ids, description = name) + params = { 'Action' => 'CreateDBSubnetGroup', + 'DBSubnetGroupName' => name, + 'DBSubnetGroupDescription' => description, + :parser => Fog::Parsers::AWS::RDS::CreateDBSubnetGroup.new } + params.merge!(Fog::AWS.indexed_param("SubnetIds.member", Array(subnet_ids))) + request(params) + end + end + + class Mock + def create_db_subnet_group(name, subnet_ids, description = name) + response = Excon::Response.new + if self.data[:subnet_groups] && self.data[:subnet_groups][name] + raise Fog::AWS::RDS::IdentifierTaken.new("DBSubnetGroupAlreadyExists => The subnet group '#{name}' already exists") + end + + # collection = Fog::Compute::AWS.new(:aws_access_key_id => 'mock key', :aws_secret_access_key => 'mock secret') + collection = Fog::Compute[:aws] + collection.region = @region + + subnets = subnet_ids.map do |snid| + subnet = collection.subnets.get(snid) + raise Fog::AWS::RDS::NotFound.new("InvalidSubnet => The subnet '#{snid}' was not found") if subnet.nil? + subnet + end + vpc_id = subnets.first.vpc_id + + data = { + 'DBSubnetGroupName' => name, + 'DBSubnetGroupDescription' => description, + 'SubnetGroupStatus' => 'Complete', + 'Subnets' => subnet_ids, + 'VpcId' => vpc_id + } + self.data[:subnet_groups][name] = data + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + 'CreateDBSubnetGroupResult' => { 'DBSubnetGroup' => data } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/create_event_subscription.rb b/lib/fog/aws/requests/rds/create_event_subscription.rb new file mode 100644 index 000000000..7cd01c7c9 --- /dev/null +++ b/lib/fog/aws/requests/rds/create_event_subscription.rb @@ -0,0 +1,67 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/create_event_subscription' + + # Subscribes a db instance to an SNS queue + # + # @see http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateEventSubscription.html + # === Parameters + # * Enabled <~Boolean> - set to true to activate the subscription, set to false to create the subscription but not active it + # * EventCategories <~Array> - A list of event categories for a SourceType that you want to subscribe to + # * SnsTopicArn <~String> - The Amazon Resource Name of the SNS topic created for event notification + # * SourceIds <~Array> - The list of identifiers of the event sources for which events will be returned + # * SourceType <~String> - The type of source that will be generating the events. For example, if you want to be notified of events generated by a DB instance, you would set this parameter to db-instance. if this value is not specified, all events are returned + # * SubscriptionName <~String> - The name of the subscription + # * Tags <~Array> - A list of tags + def create_event_subscription(options={}) + if event_categories = options.delete("EventCategories") + options.merge!(Fog::AWS.indexed_param('EventCategories.member.%d', [*event_categories])) + end + if source_ids = options.delete("SourceIds") + options.merge!(Fog::AWS.indexed_param('SourceIds.member.%d', [*source_ids])) + end + if tags = options.delete("tags") + options.merge!(Fog::AWS.indexed_param('Tags.member.%d', [*tags])) + end + + request({ + "Action" => "CreateEventSubscription", + :parser => Fog::Parsers::AWS::RDS::CreateEventSubscription.new, + }.merge(options)) + end + end + + class Mock + def create_event_subscription(options={}) + response = Excon::Response.new + name = options.delete('SubscriptionName') + arn = options.delete('SnsTopicArn') + + if self.data[:event_subscriptions][name] + raise Fog::AWS::RDS::IdentifierTaken.new("SubscriptionAlreadyExist => Subscription already exists") + end + + subscription = { + 'CustSubscriptionId' => name, + 'EventCategories' => options['EventCategories'] || [], + 'SourceType' => options['SourceType'], + 'Enabled' => options.fetch(:enabled, "true"), + 'Status' => 'creating', + 'CreationTime' => Time.now, + 'SnsTopicArn' => arn, + } + + self.data[:event_subscriptions][name] = subscription + + response.body = { + "ResponseMetaData" => {"RequestId" => Fog::AWS::Mock.request_id}, + "CreateEventSubscriptionResult" => { "EventSubscription" => subscription } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/delete_db_instance.rb b/lib/fog/aws/requests/rds/delete_db_instance.rb new file mode 100644 index 000000000..85ed2e64c --- /dev/null +++ b/lib/fog/aws/requests/rds/delete_db_instance.rb @@ -0,0 +1,51 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/delete_db_instance' + + # delete a database instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DeleteDBInstance.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - The DB Instance identifier for the DB Instance to be deleted. + # * FinalDBSnapshotIdentifier <~String> - The DBSnapshotIdentifier of the new DBSnapshot created when SkipFinalSnapshot is set to false + # * SkipFinalSnapshot <~Boolean> - Determines whether a final DB Snapshot is created before the DB Instance is deleted + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def delete_db_instance(identifier, snapshot_identifier, skip_snapshot = false) + params = {} + params['FinalDBSnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + request({ + 'Action' => 'DeleteDBInstance', + 'DBInstanceIdentifier' => identifier, + 'SkipFinalSnapshot' => skip_snapshot, + :parser => Fog::Parsers::AWS::RDS::DeleteDBInstance.new + }.merge(params)) + end + end + + class Mock + def delete_db_instance(identifier, snapshot_identifier, skip_snapshot = false) + response = Excon::Response.new + + unless skip_snapshot + create_db_snapshot(identifier, snapshot_identifier) + end + + if server_set = self.data[:servers].delete(identifier) + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DeleteDBInstanceResult" => { "DBInstance" => server_set } + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/delete_db_parameter_group.rb b/lib/fog/aws/requests/rds/delete_db_parameter_group.rb new file mode 100644 index 000000000..864de0ccd --- /dev/null +++ b/lib/fog/aws/requests/rds/delete_db_parameter_group.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/delete_db_parameter_group' + + # delete a database parameter group + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DeleteDBParameterGroup.html + # ==== Parameters + # * DBParameterGroupName <~String> - name of the parameter group. Must not be associated with any instances + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def delete_db_parameter_group(group_name) + request({ + 'Action' => 'DeleteDBParameterGroup', + 'DBParameterGroupName' => group_name, + + :parser => Fog::Parsers::AWS::RDS::DeleteDbParameterGroup.new + }) + end + end + + class Mock + def delete_db_parameter_group(group_name) + response = Excon::Response.new + + if self.data[:parameter_groups].delete(group_name) + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBParameterGroup not found: #{group_name}") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/delete_db_security_group.rb b/lib/fog/aws/requests/rds/delete_db_security_group.rb new file mode 100644 index 000000000..cf9c84b77 --- /dev/null +++ b/lib/fog/aws/requests/rds/delete_db_security_group.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/delete_db_security_group' + + # deletes a db security group + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_DeleteDBSecurityGroup.html + # ==== Parameters + # * DBSecurityGroupName <~String> - The name for the DB Security Group to delete + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def delete_db_security_group(name) + request({ + 'Action' => 'DeleteDBSecurityGroup', + 'DBSecurityGroupName' => name, + :parser => Fog::Parsers::AWS::RDS::DeleteDBSecurityGroup.new + }) + end + end + + class Mock + def delete_db_security_group(name, description = name) + response = Excon::Response.new + + if self.data[:security_groups].delete(name) + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBSecurityGroupNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/delete_db_snapshot.rb b/lib/fog/aws/requests/rds/delete_db_snapshot.rb new file mode 100644 index 000000000..352ed5c3d --- /dev/null +++ b/lib/fog/aws/requests/rds/delete_db_snapshot.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/delete_db_snapshot' + + # delete a database snapshot + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DeleteDBSnapshot.html + # ==== Parameters + # * DBSnapshotIdentifier <~String> - name of the snapshot + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def delete_db_snapshot(name) + request({ + 'Action' => 'DeleteDBSnapshot', + 'DBSnapshotIdentifier' => name, + + :parser => Fog::Parsers::AWS::RDS::DeleteDBSnapshot.new + }) + end + end + + class Mock + def delete_db_snapshot(name) + # TODO: raise error if snapshot isn't 'available' + response = Excon::Response.new + snapshot_data = self.data[:snapshots].delete(name) + + raise Fog::AWS::RDS::NotFound.new("DBSnapshtoNotFound => #{name} not found") unless snapshot_data + + response.status = 200 + response.body = { + "ResponseMetadata"=> { "RequestId"=> Fog::AWS::Mock.request_id }, + "DeleteDBSnapshotResult"=> {"DBSnapshot"=> snapshot_data} + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/delete_db_subnet_group.rb b/lib/fog/aws/requests/rds/delete_db_subnet_group.rb new file mode 100644 index 000000000..1b1fbf597 --- /dev/null +++ b/lib/fog/aws/requests/rds/delete_db_subnet_group.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/delete_db_subnet_group' + + # Deletes a db subnet group + # http://docs.aws.amazon.com/AmazonRDS/2013-09-09/APIReference/API_DeleteDBSubnetGroup.html + # ==== Parameters + # * DBSubnetGroupName <~String> - The name for the DB Subnet Group. This value is stored as a lowercase string. Must contain no more than 255 alphanumeric characters or hyphens. Must not be "Default". + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def delete_db_subnet_group(name) + params = { 'Action' => 'DeleteDBSubnetGroup', + 'DBSubnetGroupName' => name, + :parser => Fog::Parsers::AWS::RDS::DeleteDBSubnetGroup.new } + request(params) + end + end + + class Mock + def delete_db_subnet_group(name) + response = Excon::Response.new + unless self.data[:subnet_groups] && self.data[:subnet_groups][name] + raise Fog::AWS::RDS::NotFound.new("DBSubnetGroupNotFound => The subnet group '#{name}' doesn't exists") + end + + response.body = { + 'ResponseMetadata'=>{ 'RequestId'=> Fog::AWS::Mock.request_id }, + 'return' => true, + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/delete_event_subscription.rb b/lib/fog/aws/requests/rds/delete_event_subscription.rb new file mode 100644 index 000000000..0d6f88398 --- /dev/null +++ b/lib/fog/aws/requests/rds/delete_event_subscription.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/delete_event_subscription' + + # deletes an event subscription + # http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteEventSubscription.html + # === Parameters + # * SubscriptionName <~String> - The name of the subscription to delete + # === Returns + # * response<~Excon::Response>: + # * body<~Hash> + + def delete_event_subscription(name) + request({ + 'Action' => 'DeleteEventSubscription', + 'SubscriptionName' => name, + :parser => Fog::Parsers::AWS::RDS::DeleteEventSubscription.new + }) + end + end + + class Mock + def delete_event_subscription(name) + response = Excon::Response.new + + if data = self.data[:event_subscriptions][name] + data['Status'] = 'deleting' + self.data[:event_subscriptions][name] = data + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + } + response + else + raise Fog::AWS::RDS::NotFound.new("EventSubscriptionNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_engine_versions.rb b/lib/fog/aws/requests/rds/describe_db_engine_versions.rb new file mode 100644 index 000000000..491c0e07f --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_engine_versions.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_engine_versions' + + def describe_db_engine_versions(opts={}) + params = {} + params['DBParameterGroupFamily'] = opts[:db_parameter_group_family] if opts[:db_parameter_group_family] + params['DefaultOnly'] = opts[:default_only] if opts[:default_only] + params['Engine'] = opts[:engine] if opts[:engine] + params['EngineVersion'] = opts[:engine_version] if opts[:engine_version] + params['Marker'] = opts[:marker] if opts[:marker] + params['MaxRecords'] = opts[:max_records] if opts[:max_records] + + request({ + 'Action' => 'DescribeDBEngineVersions', + :parser => Fog::Parsers::AWS::RDS::DescribeDBEngineVersions.new + }.merge(params)) + end + end + + class Mock + def describe_db_engine_versions(opts={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_instances.rb b/lib/fog/aws/requests/rds/describe_db_instances.rb new file mode 100644 index 000000000..25a162f9b --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_instances.rb @@ -0,0 +1,89 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_instances' + + # Describe all or specified load db instances + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBInstances.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - ID of instance to retrieve information for. if absent information for all instances is returned + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_instances(identifier=nil, opts={}) + params = {} + params['DBInstanceIdentifier'] = identifier if identifier + if opts[:marker] + params['Marker'] = opts[:marker] + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeDBInstances', + :parser => Fog::Parsers::AWS::RDS::DescribeDBInstances.new + }.merge(params)) + end + end + + class Mock + def describe_db_instances(identifier=nil, opts={}) + response = Excon::Response.new + server_set = [] + if identifier + if server = self.data[:servers][identifier] + server_set << server + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end + else + server_set = self.data[:servers].values + end + + server_set.each do |server| + case server["DBInstanceStatus"] + when "creating" + if Time.now - server['InstanceCreateTime'] >= Fog::Mock.delay * 2 + region = "us-east-1" + server["DBInstanceStatus"] = "available" + server["AvailabilityZone"] ||= region + 'a' + server["Endpoint"] = {"Port"=>3306, + "Address"=> Fog::AWS::Mock.rds_address(server["DBInstanceIdentifier"],region) } + server["PendingModifiedValues"] = {} + end + when "rebooting" + if Time.now - self.data[:reboot_time] >= Fog::Mock.delay + # apply pending modified values + server.merge!(server["PendingModifiedValues"]) + server["PendingModifiedValues"] = {} + + server["DBInstanceStatus"] = 'available' + self.data.delete(:reboot_time) + end + when "modifying" + # TODO there are some fields that only applied after rebooting + if Time.now - self.data[:modify_time] >= Fog::Mock.delay + server.merge!(server["PendingModifiedValues"]) + server["PendingModifiedValues"] = {} + server["DBInstanceStatus"] = 'available' + end + when "available" # I'm not sure if amazon does this + unless server["PendingModifiedValues"].empty? + server["DBInstanceStatus"] = 'modifying' + end + end + end + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBInstancesResult" => { "DBInstances" => server_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_log_files.rb b/lib/fog/aws/requests/rds/describe_db_log_files.rb new file mode 100644 index 000000000..ba456fc46 --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_log_files.rb @@ -0,0 +1,64 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_log_files' + + # Describe log files for a DB instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBLogFiles.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - ID of instance to retrieve information for. Required. + # * Options <~Hash> - Hash of options. Optional. The following keys are used: + # * :file_last_written <~Long> - Filter available log files for those written after this time. Optional. + # * :file_size <~Long> - Filters the available log files for files larger than the specified size. Optional. + # * :filename_contains <~String> - Filters the available log files for log file names that contain the specified string. Optional. + # * :marker <~String> - The pagination token provided in the previous request. If this parameter is specified the response includes only records beyond the marker, up to MaxRecords. Optional. + # * :max_records <~Integer> - The maximum number of records to include in the response. If more records exist, a pagination token is included in the response. Optional. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_log_files(rds_id=nil, opts={}) + params = {} + params['DBInstanceIdentifier'] = rds_id if rds_id + params['Marker'] = opts[:marker] if opts[:marker] + params['MaxRecords'] = opts[:max_records] if opts[:max_records] + params['FilenameContains'] = opts[:filename_contains] if opts[:filename_contains] + params['FileSize'] = opts[:file_size] if opts[:file_size] + params['FileLastWritten'] = opts[:file_last_written] if opts[:file_last_written] + + request({ + 'Action' => 'DescribeDBLogFiles', + :parser => Fog::Parsers::AWS::RDS::DescribeDBLogFiles.new(rds_id) + }.merge(params)) + end + end + + class Mock + def describe_db_log_files(rds_id=nil, opts={}) + response = Excon::Response.new + log_file_set = [] + + if rds_id + if server = self.data[:servers][rds_id] + log_file_set << {"LastWritten" => Time.parse('2013-07-05 17:00:00 -0700'), "LogFileName" => "error/mysql-error.log", "Size" => 0} + log_file_set << {"LastWritten" => Time.parse('2013-07-05 17:10:00 -0700'), "LogFileName" => "error/mysql-error-running.log", "Size" => 0} + log_file_set << {"LastWritten" => Time.parse('2013-07-05 17:20:00 -0700'), "LogFileName" => "error/mysql-error-running.log.0", "Size" => 8220} + log_file_set << {"LastWritten" => Time.parse('2013-07-05 17:30:00 -0700'), "LogFileName" => "error/mysql-error-running.log.1", "Size" => 0} + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{rds_id} not found") + end + else + raise Fog::AWS::RDS::NotFound.new('An identifier for an RDS instance must be provided') + end + + response.status = 200 + response.body = { + "ResponseMetadata" => { "RequestId" => Fog::AWS::Mock.request_id }, + "DescribeDBLogFilesResult" => { "DBLogFiles" => log_file_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_parameter_groups.rb b/lib/fog/aws/requests/rds/describe_db_parameter_groups.rb new file mode 100644 index 000000000..dfa78b166 --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_parameter_groups.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_parameter_groups' + + # This API returns a list of DBParameterGroup descriptions. If a DBParameterGroupName is specified, the list will contain only the descriptions of the specified DBParameterGroup + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBParameterGroups.html + # ==== Parameters + # * DBParameterGroupName <~String> - The name of a specific database parameter group to return details for. + # * Source <~String> - The parameter types to return. user | system | engine-default + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_parameter_groups(name=nil, opts={}) + params={} + if opts[:marker] + params['Marker'] = opts[:marker] + end + if name + params['DBParameterGroupName'] = name + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeDBParameterGroups', + :parser => Fog::Parsers::AWS::RDS::DescribeDBParameterGroups.new + }.merge(params)) + end + end + + class Mock + def describe_db_parameter_groups(name=nil, opts={}) + response = Excon::Response.new + parameter_set = [] + if name + if server = self.data[:parameter_groups][name] + parameter_set << server + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{name} not found") + end + else + parameter_set = self.data[:parameter_groups].values + end + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBParameterGroupsResult" => { "DBParameterGroups" => parameter_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_parameters.rb b/lib/fog/aws/requests/rds/describe_db_parameters.rb new file mode 100644 index 000000000..5b51da422 --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_parameters.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_parameters' + + # Describe parameters from a parameter group + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBParameters.html + # ==== Parameters + # * DBParameterGroupName <~String> - name of parameter group to retrieve parameters for + # * Source <~String> - The parameter types to return. user | system | engine-default + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_parameters(name, opts={}) + params={} + if opts[:marker] + params['Marker'] = opts[:marker] + end + if opts[:source] + params['Source'] = opts[:source] + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeDBParameters', + 'DBParameterGroupName' => name, + :parser => Fog::Parsers::AWS::RDS::DescribeDBParameters.new + }.merge(params)) + end + end + + class Mock + def describe_db_parameters(name, opts={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb b/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb new file mode 100644 index 000000000..6d07d35cf --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_reserved_instances' + + # Describe all or specified load db instances + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBInstances.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - ID of instance to retrieve information for. if absent information for all instances is returned + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_reserved_instances(identifier=nil, opts={}) + params = {} + params['ReservedDBInstanceId'] = identifier if identifier + if opts[:marker] + params['Marker'] = opts[:marker] + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeReservedDBInstances', + :parser => Fog::Parsers::AWS::RDS::DescribeDBReservedInstances.new + }.merge(params)) + end + end + + class Mock + def describe_db_reserved_instances(identifier=nil, opts={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_security_groups.rb b/lib/fog/aws/requests/rds/describe_db_security_groups.rb new file mode 100644 index 000000000..946fddb4f --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_security_groups.rb @@ -0,0 +1,80 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_security_groups' + + # Describe all or specified db security groups + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_DescribeDBSecurityGroups.html + # ==== Parameters + # * DBSecurityGroupName <~String> - The name of the DB Security Group to return details for. + # * Marker <~String> - An optional marker provided in the previous DescribeDBInstances request + # * MaxRecords <~Integer> - Max number of records to return (between 20 and 100) + # Only one of DBInstanceIdentifier or DBSnapshotIdentifier can be specified + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_security_groups(opts={}) + opts = {'DBSecurityGroupName' => opts} if opts.is_a?(String) + + request({ + 'Action' => 'DescribeDBSecurityGroups', + :parser => Fog::Parsers::AWS::RDS::DescribeDBSecurityGroups.new + }.merge(opts)) + end + end + + class Mock + def describe_db_security_groups(opts={}) + response = Excon::Response.new + sec_group_set = [] + if opts.is_a?(String) + sec_group_name = opts + if sec_group = self.data[:security_groups][sec_group_name] + sec_group_set << sec_group + else + raise Fog::AWS::RDS::NotFound.new("Security Group #{sec_group_name} not found") + end + else + sec_group_set = self.data[:security_groups].values + end + + # TODO: refactor to not delete items that we're iterating over. Causes + # model tests to fail (currently pending) + sec_group_set.each do |sec_group| + sec_group["IPRanges"].each do |iprange| + if iprange["Status"] == "authorizing" || iprange["Status"] == "revoking" + iprange[:tmp] ||= Time.now + Fog::Mock.delay * 2 + if iprange[:tmp] <= Time.now + iprange["Status"] = "authorized" if iprange["Status"] == "authorizing" + iprange.delete(:tmp) + sec_group["IPRanges"].delete(iprange) if iprange["Status"] == "revoking" + end + end + end + + # TODO: refactor to not delete items that we're iterating over. Causes + # model tests to fail (currently pending) + sec_group["EC2SecurityGroups"].each do |ec2_secg| + if ec2_secg["Status"] == "authorizing" || ec2_secg["Status"] == "revoking" + ec2_secg[:tmp] ||= Time.now + Fog::Mock.delay * 2 + if ec2_secg[:tmp] <= Time.now + ec2_secg["Status"] = "authorized" if ec2_secg["Status"] == "authorizing" + ec2_secg.delete(:tmp) + sec_group["EC2SecurityGroups"].delete(ec2_secg) if ec2_secg["Status"] == "revoking" + end + end + end + end + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBSecurityGroupsResult" => { "DBSecurityGroups" => sec_group_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_snapshots.rb b/lib/fog/aws/requests/rds/describe_db_snapshots.rb new file mode 100644 index 000000000..1ab314d9e --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_snapshots.rb @@ -0,0 +1,66 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_snapshots' + + # Describe all or specified db snapshots + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBSnapshots.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - ID of instance to retrieve information for. if absent information for all instances is returned + # * DBSnapshotIdentifier <~String> - ID of snapshot to retrieve information for. if absent information for all snapshots is returned + # * SnapshotType <~String> - type of snapshot to retrive (automated|manual) + # * Marker <~String> - An optional marker provided in the previous DescribeDBInstances request + # * MaxRecords <~Integer> - Max number of records to return (between 20 and 100) + # Only one of DBInstanceIdentifier or DBSnapshotIdentifier can be specified + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_snapshots(opts={}) + params = {} + params['SnapshotType'] = opts[:type] if opts[:type] + params['DBInstanceIdentifier'] = opts[:identifier] if opts[:identifier] + params['DBSnapshotIdentifier'] = opts[:snapshot_id] if opts[:snapshot_id] + params['Marker'] = opts[:marker] if opts[:marker] + params['MaxRecords'] = opts[:max_records] if opts[:max_records] + request({ + 'Action' => 'DescribeDBSnapshots', + :parser => Fog::Parsers::AWS::RDS::DescribeDBSnapshots.new + }.merge(params)) + end + end + + class Mock + def describe_db_snapshots(opts={}) + response = Excon::Response.new + snapshots = self.data[:snapshots].values + if opts[:identifier] + snapshots = snapshots.select{|snapshot| snapshot['DBInstanceIdentifier'] == opts[:identifier]} + end + + if opts[:snapshot_id] + snapshots = snapshots.select{|snapshot| snapshot['DBSnapshotIdentifier'] == opts[:snapshot_id]} + raise Fog::AWS::RDS::NotFound.new("DBSnapshot #{opts[:snapshot_id]} not found") if snapshots.empty? + end + + snapshots.each do |snapshot| + case snapshot['Status'] + when 'creating' + if Time.now - snapshot['SnapshotCreateTime'] > Fog::Mock.delay + snapshot['Status'] = 'available' + end + end + end + + # Build response + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBSnapshotsResult" => { "DBSnapshots" => snapshots } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_db_subnet_groups.rb b/lib/fog/aws/requests/rds/describe_db_subnet_groups.rb new file mode 100644 index 000000000..36fd7008e --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_db_subnet_groups.rb @@ -0,0 +1,59 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_db_subnet_groups' + + # This API returns a list of DBSubnetGroup descriptions. If a DBSubnetGroupName is specified, the list will contain only + # the descriptions of the specified DBSubnetGroup + # http://docs.amazonwebservices.com/AmazonRDS/2012-01-15/APIReference/API_DescribeDBSubnetGroups.html + # ==== Parameters + # * DBSubnetGroupName <~String> - The name of a specific database subnet group to return details for. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_db_subnet_groups(name = nil, opts = {}) + params = {} + if opts[:marker] + params['Marker'] = opts[:marker] + end + if name + params['DBSubnetGroupName'] = name + end + if opts[:max_records] + params['MaxRecords'] = opts[:max_records] + end + + request({ + 'Action' => 'DescribeDBSubnetGroups', + :parser => Fog::Parsers::AWS::RDS::DescribeDBSubnetGroups.new + }.merge(params)) + end + end + + class Mock + def describe_db_subnet_groups(name = nil, opts = {}) + response = Excon::Response.new + + subnet_group_set = [] + if name + if subnet_group = self.data[:subnet_groups][name] + subnet_group_set << subnet_group + else + raise Fog::AWS::RDS::NotFound.new("Subnet Group #{name} not found") + end + else + subnet_group_set = self.data[:subnet_groups].values + end + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBSubnetGroupsResult" => { "DBSubnetGroups" => subnet_group_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_event_subscriptions.rb b/lib/fog/aws/requests/rds/describe_event_subscriptions.rb new file mode 100644 index 000000000..e2cc11570 --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_event_subscriptions.rb @@ -0,0 +1,61 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_event_subscriptions' + + # Describe all or specified event notifications + # http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeEventSubscriptions.html + # === Parameters + # * Marker <~String> - An optional pagination token provided by a previous DescribeOrderableDBInstanceOptions request + # * MaxRecords <~String> - The maximum number of records to include in the response (20-100) + # * SubscriptionName <~String> - The name of the RDS event notification subscription you want to describe + # === Returns + # * response<~Excon::Response>: + # * body<~Hash> + def describe_event_subscriptions(options={}) + if options[:max_records] + params['MaxRecords'] = options[:max_records] + end + + request({ + 'Action' => 'DescribeEventSubscriptions', + :parser => Fog::Parsers::AWS::RDS::DescribeEventSubscriptions.new + }.merge(options)) + end + end + + class Mock + def describe_event_subscriptions(options={}) + response = Excon::Response.new + name = options['SubscriptionName'] + + subscriptions = self.data[:event_subscriptions].values + subscriptions = subscriptions.select { |s| s['CustSubscriptionId'] == name } if name + + non_active = self.data[:event_subscriptions].values.select { |s| s['Status'] != 'active' } + + non_active.each do |s| + name = s['CustSubscriptionId'] + if s['Status'] == 'creating' + s['Status'] = 'active' + self.data[:event_subscriptions][name] = s + elsif s['Status'] == 'deleting' + self.data[:event_subscriptions].delete(name) + end + end + + if options['SubscriptionName'] && subscriptions.empty? + raise Fog::AWS::RDS::NotFound.new("Event Subscription #{options['SubscriptionName']} not found.") + end + + response.body = { + "ResponseMetadata" => {"RequestId" => Fog::AWS::Mock.request_id}, + "DescribeEventSubscriptionsResult" => {"EventSubscriptionsList" => subscriptions} + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_events.rb b/lib/fog/aws/requests/rds/describe_events.rb new file mode 100644 index 000000000..488b07a5e --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_events.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/event_list' + + # Returns a list of service events + # + # For more information see: + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeEvents.html + # + # === Parameters (optional) + # * options <~Hash> (optional): + # * :start_time <~DateTime> - starting time for event records + # * :end_time <~DateTime> - ending time for event records + # * :duration <~Integer> - The number of minutes to retrieve events for + # Default = 60 Mins + # * :marker <~String> - marker provided in the previous request + # * :max_records <~Integer> - the maximum number of records to include + # Default = 100 + # Constraints: min = 20, maximum 100 + # * :source_identifier <~String> - identifier of the event source + # * :source_type <~DateTime> - event type, one of: + # (db-instance | db-parameter-group | db-security-group | db-snapshot) + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def describe_events(options = {}) + request( + 'Action' => 'DescribeEvents', + 'StartTime' => options[:start_time], + 'EndTime' => options[:end_time], + 'Duration' => options[:duration], + 'Marker' => options[:marker], + 'MaxRecords' => options[:max_records], + 'SourceIdentifier' => options[:source_identifier], + 'SourceType' => options[:source_type], + :parser => Fog::Parsers::AWS::RDS::EventListParser.new + ) + end + end + + class Mock + def describe_events + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb new file mode 100644 index 000000000..95d147ff2 --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb @@ -0,0 +1,72 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/describe_orderable_db_instance_options' + + # Describe all or specified load db instances + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBInstances.html + # ==== Parameters + # * Engine <~String> - The name of the engine to retrieve DB Instance options for. Required. + # * Options <~Hash> - Hash of options. Optional. The following keys are used: + # * :db_instance_class <~String> - Filter available offerings matching the specified DB Instance class. Optional. + # * :engine_version <~String> - Filters available offerings matching the specified engine version. Optional. + # * :license_model <~String> - Filters available offerings matching the specified license model. Optional. + # * :marker <~String> - The pagination token provided in the previous request. If this parameter is specified the response includes only records beyond the marker, up to MaxRecords. Optional. + # * :max_records <~Integer> - The maximum number of records to include in the response. If more records exist, a pagination token is included in the response. Optional. + # * :vpc <~Boolean> - Filter to show only the available VPC or non-VPC offerings. Optional. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_orderable_db_instance_options(engine=nil, opts={}) + params = {} + params['Engine'] = engine if engine + params['DBInstanceClass'] = opts[:db_instance_class] if opts[:db_instance_class] + params['EngineVersion'] = opts[:engine_version] if opts[:engine_version] + params['LicenseModel'] = opts[:license_model] if opts[:license_model] + params['Marker'] = opts[:marker] if opts[:marker] + params['MaxRecords'] = opts[:max_records] if opts[:max_records] + params['Vpc'] = opts[:vpc] if opts[:vpc] + + request({ + 'Action' => 'DescribeOrderableDBInstanceOptions', + :parser => Fog::Parsers::AWS::RDS::DescribeOrderableDBInstanceOptions.new + }.merge(params)) + end + end + + class Mock + def describe_orderable_db_instance_options(engine=nil, opts={}) + instance_options = [] + response = Excon::Response.new + if engine + (opts[:db_instance_class] || %w(db.m2.xlarge db.m1.large)).each do |size| + instance_options << {'MultiAZCapable' => true, + 'Engine' => engine, + 'LicenseModel' => opts[:license_model] || 'general-public-license', + 'ReadReplicaCapable' => true, + 'EngineVersion' => opts[:engine_version] || '5.6.12', + 'AvailabilityZones' => [ + {'Name' => 'us-east-1b', 'ProvisionedIopsCapable' => true}, + {'Name' => 'us-east-1c', 'ProvisionedIopsCapable' => true}, + {'Name' => 'us-east-1d', 'ProvisionedIopsCapable' => false}, + {'Name' => 'us-east-1e', 'ProvisionedIopsCapable' => true}], + 'DBInstanceClass' => size, + 'Vpc' => opts[:vpc].nil? ? true : opts[:vpc]} + + end + else + raise Fog::AWS::RDS::NotFound.new('An engine must be specified to retrieve orderable instance options') + end + + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id }, + 'DescribeOrderableDBInstanceOptionsResult' => { 'OrderableDBInstanceOptions' => instance_options } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/download_db_logfile_portion.rb b/lib/fog/aws/requests/rds/download_db_logfile_portion.rb new file mode 100644 index 000000000..e8361b34d --- /dev/null +++ b/lib/fog/aws/requests/rds/download_db_logfile_portion.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/download_db_logfile_portion' + + # Retrieve a portion of a log file of a db instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DownloadDBLogFilePortion.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - ID of instance to retrieve information for. Required. + # * LogFileName <~String> - The name of the log file to be downloaded. Required. + # * Options <~Hash> - Hash of options. Optional. The following keys are used: + # * :marker <~String> - The pagination token provided in the previous request. If this parameter is specified the response includes only records beyond the marker, up to MaxRecords. Optional. + # * :max_records <~Integer> - The maximum number of records to include in the response. If more records exist, a pagination token is included in the response. Optional. + # * :number_of_lines <~Integer> - The number of lines to download. Optional. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def download_db_logfile_portion(identifier=nil, filename=nil, opts={}) + params = {} + params['DBInstanceIdentifier'] = identifier if identifier + params['LogFileName'] = filename if filename + params['Marker'] = opts[:marker] if opts[:marker] + params['MaxRecords'] = opts[:max_records] if opts[:max_records] + params['NumberOfLines'] = opts[:number_of_lines] if opts[:number_of_lines] + + request({ + 'Action' => 'DownloadDBLogFilePortion', + :parser => Fog::Parsers::AWS::RDS::DownloadDBLogFilePortion.new + }.merge(params)) + end + end + + class Mock + def download_db_logfile_portion(identifier=nil, filename=nil, opts={}) + response = Excon::Response.new + server_set = [] + if identifier + if server = self.data[:servers][identifier] + server_set << server + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end + else + server_set = self.data[:servers].values + end + + response.status = 200 + response.body = { + "ResponseMetadata" => { "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBInstancesResult" => { "DBInstances" => server_set } + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/list_tags_for_resource.rb b/lib/fog/aws/requests/rds/list_tags_for_resource.rb new file mode 100644 index 000000000..c02d1e29c --- /dev/null +++ b/lib/fog/aws/requests/rds/list_tags_for_resource.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/tag_list_parser' + + # returns a Hash of tags for a database instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_ListTagsForResource.html + # ==== Parameters + # * rds_id <~String> - name of the RDS instance whose tags are to be retrieved + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def list_tags_for_resource(rds_id) + request( + 'Action' => 'ListTagsForResource', + 'ResourceName' => "arn:aws:rds:#{@region}:#{owner_id}:db:#{rds_id}", + :parser => Fog::Parsers::AWS::RDS::TagListParser.new + ) + end + end + + class Mock + def list_tags_for_resource(rds_id) + response = Excon::Response.new + if server = self.data[:servers][rds_id] + response.status = 200 + response.body = { + "ListTagsForResourceResult" => + {"TagList" => self.data[:tags][rds_id]} + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{rds_id} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/modify_db_instance.rb b/lib/fog/aws/requests/rds/modify_db_instance.rb new file mode 100644 index 000000000..997a32f9b --- /dev/null +++ b/lib/fog/aws/requests/rds/modify_db_instance.rb @@ -0,0 +1,81 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/modify_db_instance' + + # modifies a database instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - name of the db instance to modify + # * ApplyImmediately <~Boolean> - whether to apply the changes immediately or wait for the next maintenance window + # + # * AllocatedStorage <~Integer> Storage space, in GB + # * AllowMajorVersionUpgrade <~Boolean> Must be set to true if EngineVersion specifies a different major version + # * AutoMinorVersionUpgrade <~Boolean> Indicates that minor version upgrades will be applied automatically to the DB Instance during the maintenance window + # * BackupRetentionPeriod <~Integer> 0-8 The number of days to retain automated backups. + # * DBInstanceClass <~String> The new compute and memory capacity of the DB Instanc + # * DBParameterGroupName <~String> The name of the DB Parameter Group to apply to this DB Instance + # * DBSecurityGroups <~Array> A list of DB Security Groups to authorize on this DB Instance + # * EngineVersion <~String> The version number of the database engine to upgrade to. + # * Iops <~Integer> IOPS rate + # * MasterUserPassword <~String> The new password for the DB Instance master user + # * MultiAZ <~Boolean> Specifies if the DB Instance is a Multi-AZ deployment + # * PreferredBackupWindow <~String> The daily time range during which automated backups are created if automated backups are enabled + # * PreferredMaintenanceWindow <~String> The weekly time range (in UTC) during which system maintenance can occur, which may result in an outage + # * VpcSecurityGroups <~Array> A list of VPC Security Group IDs to authorize on this DB instance + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def modify_db_instance(db_name, apply_immediately, options={}) + if security_groups = options.delete('DBSecurityGroups') + options.merge!(Fog::AWS.indexed_param('DBSecurityGroups.member.%d', [*security_groups])) + end + + if vpc_security_groups = options.delete('VpcSecurityGroups') + options.merge!(Fog::AWS.indexed_param('VpcSecurityGroupIds.member.%d', [*vpc_security_groups])) + end + + request({ + 'Action' => 'ModifyDBInstance', + 'DBInstanceIdentifier' => db_name, + 'ApplyImmediately' => apply_immediately, + :parser => Fog::Parsers::AWS::RDS::ModifyDBInstance.new, + }.merge(options)) + end + end + + class Mock + def modify_db_instance(db_name, apply_immediately, options={}) + response = Excon::Response.new + if self.data[:servers][db_name] + if self.data[:servers][db_name]["DBInstanceStatus"] != "available" + raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not available for modification") + else + self.data[:modify_time] = Time.now + # TODO verify the params options + # if apply_immediately is false, all the options go to pending_modified_values and then apply and clear after either + # a reboot or the maintainance window + #if apply_immediately + # modified_server = server.merge(options) + #else + # modified_server = server["PendingModifiedValues"].merge!(options) # it appends + #end + self.data[:servers][db_name]["PendingModifiedValues"].merge!(options) # it appends + self.data[:servers][db_name]["DBInstanceStatus"] = "modifying" + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "ModifyDBInstanceResult" => { "DBInstance" => self.data[:servers][db_name] } + } + response + + end + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/modify_db_parameter_group.rb b/lib/fog/aws/requests/rds/modify_db_parameter_group.rb new file mode 100644 index 000000000..9a03bac27 --- /dev/null +++ b/lib/fog/aws/requests/rds/modify_db_parameter_group.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/modify_db_parameter_group' + + # modifies a database parameter group + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_ModifyDBParameterGroup.html + # ==== Parameters + # * DBParameterGroupName <~String> - name of the parameter group + # * Parameters<~Array> - Array of up to 20 Hashes describing parameters to set + # * 'ParameterName'<~String> - parameter name. + # * 'ParameterValue'<~String> - new paremeter value + # * 'ApplyMethod'<~String> - immediate | pending-reboot whether to set the parameter immediately or not (may require an instance restart) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def modify_db_parameter_group(group_name, parameters) + parameter_names = [] + parameter_values = [] + parameter_apply_methods = [] + + parameters.each do |parameter| + parameter_names.push(parameter['ParameterName']) + parameter_values.push(parameter['ParameterValue']) + parameter_apply_methods.push(parameter['ApplyMethod']) + end + params = {} + params.merge!(Fog::AWS.indexed_param('Parameters.member.%d.ParameterName', parameter_names)) + params.merge!(Fog::AWS.indexed_param('Parameters.member.%d.ParameterValue', parameter_values)) + params.merge!(Fog::AWS.indexed_param('Parameters.member.%d.ApplyMethod', parameter_apply_methods)) + + request({ + 'Action' => 'ModifyDBParameterGroup', + 'DBParameterGroupName' => group_name, + + :parser => Fog::Parsers::AWS::RDS::ModifyDbParameterGroup.new + }.merge(params)) + end + end + + class Mock + def modify_db_parameter_group(group_name, parameters) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/promote_read_replica.rb b/lib/fog/aws/requests/rds/promote_read_replica.rb new file mode 100644 index 000000000..68388bbb3 --- /dev/null +++ b/lib/fog/aws/requests/rds/promote_read_replica.rb @@ -0,0 +1,59 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/promote_read_replica' + + # promote a read replica to a writable RDS instance + # http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_PromoteReadReplica.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - The DB Instance identifier for the DB Instance to be deleted. + # * BackupRetentionPeriod <~Integer> - The number of days to retain automated backups. Range: 0-8. + # Setting this parameter to a positive number enables backups. + # Setting this parameter to 0 disables automated backups. + # * PreferredBackupWindow <~String> - The daily time range during which automated backups are created if + # automated backups are enabled, using the BackupRetentionPeriod parameter. + # Default: A 30-minute window selected at random from an 8-hour block of time per region. + # See the Amazon RDS User Guide for the time blocks for each region from which the default backup windows are assigned. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + + def promote_read_replica(identifier, backup_retention_period = nil, preferred_backup_window = nil) + params = {} + params['BackupRetentionPeriod'] = backup_retention_period if backup_retention_period + params['PreferredBackupWindow'] = preferred_backup_window if preferred_backup_window + request({ + 'Action' => 'PromoteReadReplica', + 'DBInstanceIdentifier' => identifier, + :parser => Fog::Parsers::AWS::RDS::PromoteReadReplica.new + }.merge(params)) + end + end + + class Mock + def promote_read_replica(identifier, backup_retention_period = nil, preferred_backup_window = nil) + if self.data[:servers][identifier] + data = { + 'BackupRetentionPeriod' => backup_retention_period || 1, + 'PreferredBackupWindow' => preferred_backup_window || '08:00-08:30', + 'DBInstanceIdentifier' => identifier + } + self.data[:servers][identifier].merge(data) + + response = Excon::Response.new + response.body = { + "ResponseMetadata" => { "RequestId" => Fog::AWS::Mock.request_id }, + "PromoteReadReplicaResult" => { "DBInstance" => data} + } + response.status = 200 + response + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/reboot_db_instance.rb b/lib/fog/aws/requests/rds/reboot_db_instance.rb new file mode 100644 index 000000000..c7f942191 --- /dev/null +++ b/lib/fog/aws/requests/rds/reboot_db_instance.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/reboot_db_instance' + + # reboots a database instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_RebootDBInstance.html + # ==== Parameters + # * DBInstanceIdentifier <~String> - name of the db instance to reboot + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def reboot_db_instance(instance_identifier) + request({ + 'Action' => 'RebootDBInstance', + 'DBInstanceIdentifier' => instance_identifier, + :parser => Fog::Parsers::AWS::RDS::RebootDBInstance.new, + }) + end + end + + class Mock + def reboot_db_instance(instance_identifier) + response = Excon::Response.new + if server = self.data[:servers][instance_identifier] + if server["DBInstanceStatus"] != "available" + raise Fog::AWS::RDS::NotFound.new("DBInstance #{instance_identifier} not available for rebooting") + else + server["DBInstanceStatus"] = 'rebooting' + self.data[:reboot_time] = Time.now + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "RebootDBInstanceResult" => { "DBInstance" => server } + } + response + + end + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{instance_identifier} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/remove_tags_from_resource.rb b/lib/fog/aws/requests/rds/remove_tags_from_resource.rb new file mode 100644 index 000000000..be84c17d9 --- /dev/null +++ b/lib/fog/aws/requests/rds/remove_tags_from_resource.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class RDS + class Real + # removes tags from a database instance + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_RemoveTagsFromResource.html + # ==== Parameters + # * rds_id <~String> - name of the RDS instance whose tags are to be retrieved + # * keys <~Array> A list of String keys for the tags to remove + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def remove_tags_from_resource(rds_id, keys) + request( + { 'Action' => 'RemoveTagsFromResource', + 'ResourceName' => "arn:aws:rds:#{@region}:#{owner_id}:db:#{rds_id}", + :parser => Fog::Parsers::AWS::RDS::Base.new, + }.merge(Fog::AWS.indexed_param('TagKeys.member.%d', keys)) + ) + end + end + + class Mock + def remove_tags_from_resource(rds_id, keys) + response = Excon::Response.new + if server = self.data[:servers][rds_id] + keys.each {|key| self.data[:tags][rds_id].delete key} + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id } + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{rds_id} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/restore_db_instance_from_db_snapshot.rb b/lib/fog/aws/requests/rds/restore_db_instance_from_db_snapshot.rb new file mode 100644 index 000000000..e998d3065 --- /dev/null +++ b/lib/fog/aws/requests/rds/restore_db_instance_from_db_snapshot.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/restore_db_instance_from_db_snapshot' + + # Restores a DB Instance from a DB Snapshot + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_RestoreDBInstanceFromDBSnapshot.html + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def restore_db_instance_from_db_snapshot(snapshot_id, db_name, opts={}) + request({ + 'Action' => 'RestoreDBInstanceFromDBSnapshot', + 'DBSnapshotIdentifier' => snapshot_id, + 'DBInstanceIdentifier' => db_name, + :parser => Fog::Parsers::AWS::RDS::RestoreDBInstanceFromDBSnapshot.new, + }.merge(opts)) + end + end + + class Mock + def restore_db_instance_from_db_snapshot(snapshot_id, db_id, options={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/restore_db_instance_to_point_in_time.rb b/lib/fog/aws/requests/rds/restore_db_instance_to_point_in_time.rb new file mode 100644 index 000000000..271e6fe2a --- /dev/null +++ b/lib/fog/aws/requests/rds/restore_db_instance_to_point_in_time.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/restore_db_instance_to_point_in_time' + + # Restores a DB Instance to a point in time + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_RestoreDBInstanceToPointInTime.html + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def restore_db_instance_to_point_in_time(source_db_name, target_db_name, opts={}) + request({ + 'Action' => 'RestoreDBInstanceToPointInTime', + 'SourceDBInstanceIdentifier' => source_db_name, + 'TargetDBInstanceIdentifier' => target_db_name, + :parser => Fog::Parsers::AWS::RDS::RestoreDBInstanceToPointInTime.new, + }.merge(opts)) + end + end + + class Mock + def restore_db_instance_to_point_in_time(source_db_name, target_db_name, opts={}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/rds/revoke_db_security_group_ingress.rb b/lib/fog/aws/requests/rds/revoke_db_security_group_ingress.rb new file mode 100644 index 000000000..87ffda3cc --- /dev/null +++ b/lib/fog/aws/requests/rds/revoke_db_security_group_ingress.rb @@ -0,0 +1,63 @@ +module Fog + module AWS + class RDS + class Real + require 'fog/aws/parsers/rds/revoke_db_security_group_ingress' + + # revokes a db security group ingress + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/index.html?API_RevokeDBSecurityGroupIngress.html + # ==== Parameters + # * CIDRIP <~String> - The IP range to revoke + # * DBSecurityGroupName <~String> - The name for the DB Security Group. + # * EC2SecurityGroupName <~String> - Name of the EC2 Security Group to revoke. + # * EC2SecurityGroupOwnerId <~String> - Aws Account Number of the owner of the security group specified in the EC2SecurityGroupName parameter. The Aws Access Key ID is not an acceptable value. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def revoke_db_security_group_ingress(name, opts={}) + unless opts.key?('CIDRIP') || (opts.key?('EC2SecurityGroupName') && opts.key?('EC2SecurityGroupOwnerId')) + raise ArgumentError, 'Must specify CIDRIP, or both EC2SecurityGroupName and EC2SecurityGroupOwnerId' + end + + request({ + 'Action' => 'RevokeDBSecurityGroupIngress', + :parser => Fog::Parsers::AWS::RDS::RevokeDBSecurityGroupIngress.new, + 'DBSecurityGroupName' => name + }.merge(opts)) + end + end + + class Mock + def revoke_db_security_group_ingress(name, opts = {}) + unless opts.key?('CIDRIP') || (opts.key?('EC2SecurityGroupName') && opts.key?('EC2SecurityGroupOwnerId')) + raise ArgumentError, 'Must specify CIDRIP, or both EC2SecurityGroupName and EC2SecurityGroupOwnerId' + end + + response = Excon::Response.new + + if sec_group = self.data[:security_groups][name] + if opts.key?('CIDRIP') + sec_group['IPRanges'].each do |iprange| + iprange['Status']= 'revoking' if iprange['CIDRIP'] == opts['CIDRIP'] + end + else + sec_group['EC2SecurityGroups'].each do |ec2_secg| + ec2_secg['Status']= 'revoking' if ec2_secg['EC2SecurityGroupName'] == opts['EC2SecurityGroupName'] + end + end + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + 'RevokeDBSecurityGroupIngressResult' => { + 'DBSecurityGroup' => sec_group + } + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBSecurityGroupNotFound => #{name} not found") + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/authorize_cluster_security_group_ingress.rb b/lib/fog/aws/requests/redshift/authorize_cluster_security_group_ingress.rb new file mode 100644 index 000000000..0c1ca58e2 --- /dev/null +++ b/lib/fog/aws/requests/redshift/authorize_cluster_security_group_ingress.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/revoke_cluster_security_group_ingress' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_security_group_name - required - (String) + # The name of the security Group from which to revoke the ingress rule. + # * :cidrip - (String) + # The IP range for which to revoke access. This range must be a valid Classless + # Inter-Domain Routing (CIDR) block of IP addresses. If CIDRIP is specified, + # EC2SecurityGroupName and EC2SecurityGroupOwnerId cannot be provided. + # * :ec2_security_group_name - (String) + # The name of the EC2 Security Group whose access is to be revoked. If + # EC2SecurityGroupName is specified, EC2SecurityGroupOwnerId must also be + # provided and CIDRIP cannot be provided. + # * :ec2_security_group_owner_id - (String) + # The Aws account number of the owner of the security group specified in the + # EC2SecurityGroupName parameter. The Aws access key ID is not an acceptable + # value. If EC2SecurityGroupOwnerId is specified, EC2SecurityGroupName must + # also be provided. and CIDRIP cannot be provided. Example: 111122223333 + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_AuthorizeClusterSecurityGroupIngress.html + def authorize_cluster_security_group_ingress(options = {}) + cluster_security_group_name = options[:cluster_security_group_name] + cidrip = options[:cidrip] + ec2_security_group_name = options[:ec2_security_group_name] + ec2_security_group_owner_id = options[:ec2_security_group_owner_id] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::RevokeClusterSecurityGroupIngress.new + } + + params[:query]['Action'] = 'AuthorizeClusterSecurityGroupIngress' + params[:query]['ClusterSecurityGroupName'] = cluster_security_group_name if cluster_security_group_name + params[:query]['CIDRIP'] = cidrip if cidrip + params[:query]['EC2SecurityGroupName'] = ec2_security_group_name if ec2_security_group_name + params[:query]['EC2SecurityGroupOwnerId'] = ec2_security_group_owner_id if ec2_security_group_owner_id + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/authorize_snapshot_access.rb b/lib/fog/aws/requests/redshift/authorize_snapshot_access.rb new file mode 100644 index 000000000..4372edfb4 --- /dev/null +++ b/lib/fog/aws/requests/redshift/authorize_snapshot_access.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_snapshot' + + # ==== Parameters + # + # @param [Hash] options + # * :snapshot_identifier - required - (String) + # The identifier of the snapshot the account is authorized to restore. + # * :snapshot_cluster_identifier - (String) + # * :account_with_restore_access - required - (String) + # The identifier of the Aws customer account authorized to restore the specified snapshot. # + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CopyClusterSnapshot.html + def authorize_snapshot_access(options = {}) + snapshot_identifier = options[:snapshot_identifier] + snapshot_cluster_identifier = options[:snapshot_cluster_identifier] + account_with_restore_access = options[:account_with_restore_access] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSnapshot.new + } + + params[:query]['Action'] = 'AuthorizeSnapshotAccess' + params[:query]['SnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + params[:query]['SnapshotClusterIdentifier'] = snapshot_cluster_identifier if snapshot_cluster_identifier + params[:query]['AccountWithRestoreAccess'] = account_with_restore_access if account_with_restore_access + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/copy_cluster_snapshot.rb b/lib/fog/aws/requests/redshift/copy_cluster_snapshot.rb new file mode 100644 index 000000000..7f18bdea8 --- /dev/null +++ b/lib/fog/aws/requests/redshift/copy_cluster_snapshot.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_snapshot' + + # ==== Parameters + # + # @param [Hash] options + # * :source_snapshot_identifier - required - (String) + # The identifier for the source snapshot. Constraints: Must be the identifier for + # a valid automated snapshot whose state is "available". + # * :source_snapshot_cluster_identifier - (String) + # * :target_snapshot_identifier - required - (String) + # The identifier given to the new manual snapshot. Constraints: Cannot be null, + # empty, or blank. Must contain from 1 to 255 alphanumeric characters or hyphens. + # First character must be a letter. Cannot end with a hyphen or contain two + # consecutive hyphens. Must be unique for the Aws account that is making the request. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CopyClusterSnapshot.html + def copy_cluster_snapshot(options = {}) + source_snapshot_identifier = options[:source_snapshot_identifier] + source_snapshot_cluster_identifier = options[:source_snapshot_cluster_identifier] + target_snapshot_identifier = options[:target_snapshot_identifier] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSnapshot.new + } + + params[:query]['Action'] = 'CopyClusterSnapshot' + params[:query]['SourceSnapshotIdentifier'] = source_snapshot_identifier if source_snapshot_identifier + params[:query]['SourceSnapshotClusterIdentifier'] = source_snapshot_cluster_identifier if source_snapshot_cluster_identifier + params[:query]['TargetSnapshotIdentifier'] = target_snapshot_identifier if target_snapshot_identifier + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/create_cluster.rb b/lib/fog/aws/requests/redshift/create_cluster.rb new file mode 100644 index 000000000..47cb8133c --- /dev/null +++ b/lib/fog/aws/requests/redshift/create_cluster.rb @@ -0,0 +1,148 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster' + + # ==== Parameters + # + # @param [Hash] options + # * :db_name - (String) + # The name of the first database to be created when the cluster is created. To create + # additional databases after the cluster is created, connect to the cluster with a SQL + # client and use SQL commands to create a database. Default: dev Constraints: Must + # contain 1 to 64 alphanumeric characters. Must contain only lowercase letters. + # * :cluster_identifier - required - (String) + # A unique identifier for the cluster. You use this identifier to refer to the cluster + # for any subsequent cluster operations such as deleting or modifying. Must be unique + # for all clusters within an Aws account. Example: myexamplecluster + # * :cluster_type - (String) + # Type of the cluster. When cluster type is specified as single-node, the NumberOfNodes + # parameter is not required. multi-node, the NumberOfNodes parameter is required. Valid + # Values: multi-node | single-node Default: multi-node + # * :node_type - required - (String) + # The node type to be provisioned. Valid Values: dw.hs1.xlarge | dw.hs1.8xlarge. + # * :master_username - required - (String) + # The user name associated with the master user account for the cluster that is being + # created. Constraints: Must be 1 - 128 alphanumeric characters. First character must + # be a letter. Cannot be a reserved word. + # * :master_user_password - required - (String) + # The password associated with the master user account for the cluster that is being + # created. Constraints: Must be between 8 and 64 characters in length. Must contain at + # least one uppercase letter. Must contain at least one lowercase letter. Must contain + # one number. + # * :cluster_security_groups - (Array) + # A list of security groups to be associated with this cluster. Default: The default + # cluster security group for Amazon Redshift. + # * :vpc_security_group_ids - (Array) + # A list of Virtual Private Cloud (VPC) security groups to be associated with the + # cluster. Default: The default VPC security group is associated with the cluster. + # * :cluster_subnet_group_name - (String) + # The name of a cluster subnet group to be associated with this cluster. If this + # parameter is not provided the resulting cluster will be deployed outside virtual + # private cloud (VPC). + # * :availability_zone - (String) + # The EC2 Availability Zone (AZ) in which you want Amazon Redshift to provision the + # cluster. Default: A random, system-chosen Availability Zone in the region that is + # specified by the endpoint. Example: us-east-1d Constraint: The specified + # Availability Zone must be in the same region as the current endpoint. + # * :preferred_maintenance_window - (String) + # The weekly time range (in UTC) during which automated cluster maintenance can occur. + # Format: ddd:hh24:mi-ddd:hh24:mi Default: A 30-minute window selected at random from + # an 8-hour block of time per region, occurring on a random day of the week. + # Constraints: Minimum 30-minute window. + # * :cluster_parameter_group_name - (String) + # The name of the parameter group to be associated with this cluster. Default: The + # default Amazon Redshift cluster parameter group. Constraints: Must be 1 to 255 + # alphanumeric characters or hyphens. First character must be a letter. Cannot end + # with a hyphen or contain two consecutive hyphens. + # * :automated_snapshot_retention_period - (Integer) + # Number of days that automated snapshots are retained. If the value is 0, automated + # snapshots are disabled. Default: 1 Constraints: Must be a value from 0 to 35. + # * :port - (Integer) + # The port number on which the cluster accepts incoming connections. Default: 5439 + # Valid Values: 1150-65535 + # * :cluster_version - (String) + # The version of the Amazon Redshift engine software that you want to deploy on the + # cluster. The version selected runs on all the nodes in the cluster. Constraints: + # Only version 1.0 is currently available. Example: 1.0 + # * :allow_version_upgrade - (Boolean) + # If `true` , upgrades can be applied during the maintenance window to the Amazon + # Redshift engine that is running on the cluster. Default: `true` + # * :number_of_nodes - (Integer) + # The number of compute nodes in the cluster. This parameter is required when the + # ClusterType parameter is specified as multi-node. If you don't specify this parameter, + # you get a single-node cluster. When requesting a multi-node cluster, you must specify + # the number of nodes that you want in the cluster. Default: 1 Constraints: Value must + # be at least 1 and no more than 100. + # * :publicly_accessible - (Boolean) + # If `true` , the cluster can be accessed from a public network. + # * :encrypted - (Boolean) + # If `true` , the data in cluster is encrypted at rest. Default: `false` + + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateCluster.html + def create_cluster(options = {}) + db_name = options[:db_name] + cluster_identifier = options[:cluster_identifier] + cluster_type = options[:cluster_type] + node_type = options[:node_type] + master_username = options[:master_username] + master_user_password = options[:master_user_password] + cluster_subnet_group_name = options[:cluster_subnet_group_name] + availability_zone = options[:availability_zone] + preferred_maintenance_window = options[:preferred_maintenance_window] + cluster_parameter_group_name = options[:cluster_parameter_group_name] + automated_snapshot_retention_period = options[:automated_snapshot_retention_period] + port = options[:port] + cluster_version = options[:cluster_version] + allow_version_upgrade = options[:allow_version_upgrade] + number_of_nodes = options[:number_of_nodes] + publicly_accessible = options[:publicly_accessible] + encrypted = options[:encrypted] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::Cluster.new + } + + if cluster_security_groups = options.delete(:ClusterSecurityGroups) + params[:query].merge!(Fog::AWS.indexed_param('ClusterSecurityGroups.member.%d', [*cluster_security_groups])) + end + + if vpc_security_group_ids = options.delete(:VpcSecurityGroupIds) + params[:query].merge!(Fog::AWS.indexed_param('VpcSecurityGroupIds.member.%d', [*vpc_security_group_ids])) + end + + params[:query]['Action'] = 'CreateCluster' + params[:query]['DBName'] = db_name if db_name + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + params[:query]['ClusterType'] = cluster_type if cluster_type + params[:query]['NodeType'] = node_type if node_type + params[:query]['MasterUsername'] = master_username if master_username + params[:query]['MasterUserPassword'] = master_user_password if master_user_password + params[:query]['ClusterSecurityGroups'] = cluster_security_groups if cluster_security_groups + params[:query]['VpcSecurityGroupIds'] = vpc_security_group_ids if vpc_security_group_ids + params[:query]['ClusterSubnetGroupName'] = cluster_subnet_group_name if cluster_subnet_group_name + params[:query]['AvailabilityZone'] = availability_zone if availability_zone + params[:query]['PreferredMaintenanceWindow'] = preferred_maintenance_window if preferred_maintenance_window + params[:query]['ClusterParameterGroupName'] = cluster_parameter_group_name if cluster_parameter_group_name + params[:query]['AutomatedSnapshotRetentionPeriod'] = automated_snapshot_retention_period if automated_snapshot_retention_period + params[:query]['Port'] = port if port + params[:query]['ClusterVersion'] = cluster_version if cluster_version + params[:query]['AllowVersionUpgrade'] = allow_version_upgrade if allow_version_upgrade + params[:query]['NumberOfNodes'] = number_of_nodes if number_of_nodes + params[:query]['PubliclyAccessible'] = publicly_accessible if publicly_accessible + params[:query]['Encrypted'] = encrypted if encrypted + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/create_cluster_parameter_group.rb b/lib/fog/aws/requests/redshift/create_cluster_parameter_group.rb new file mode 100644 index 000000000..3965d1289 --- /dev/null +++ b/lib/fog/aws/requests/redshift/create_cluster_parameter_group.rb @@ -0,0 +1,53 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/create_cluster_parameter_group' + + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_name - required - (String) + # The name of the cluster parameter group. Constraints: Must be 1 to 255 alphanumeric + # characters or hyphens First character must be a letter. Cannot end with a hyphen or + # contain two consecutive hyphens. Must be unique within your Aws account. This value + # is stored as a lower-case string. + # * :parameter_group_family - required - (String) + # The Amazon Redshift engine version to which the cluster parameter group applies. The + # cluster engine version determines the set of parameters. To get a list of valid parameter + # group family names, you can call DescribeClusterParameterGroups. By default, Amazon + # Redshift returns a list of all the parameter groups that are owned by your Aws account, + # including the default parameter groups for each Amazon Redshift engine version. The + # parameter group family names associated with the default parameter groups provide you + # the valid values. For example, a valid family name is "redshift-1.0". + # * :description - required - (String) + # A description of the parameter group. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateClusterParameterGroup.html + def create_cluster_parameter_group(options = {}) + parameter_group_name = options[:parameter_group_name] + parameter_group_family = options[:parameter_group_family] + description = options[:description] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::CreateClusterParameterGroup.new + } + + params[:query]['Action'] = 'CreateClusterParameterGroup' + params[:query]['ParameterGroupName'] = parameter_group_name if parameter_group_name + params[:query]['ParameterGroupFamily'] = parameter_group_family if parameter_group_family + params[:query]['Description'] = description if description + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/create_cluster_security_group.rb b/lib/fog/aws/requests/redshift/create_cluster_security_group.rb new file mode 100644 index 000000000..c0d6c665f --- /dev/null +++ b/lib/fog/aws/requests/redshift/create_cluster_security_group.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/create_cluster_security_group' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_security_group_name - (String) + # The name of a cluster security group for which you are requesting details. You + # can specify either the Marker parameter or a ClusterSecurityGroupName parameter, + # but not both. Example: securitygroup1 + # * :description - required - (String) + # A description for the security group. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateClusterSecurityGroup.html + def create_cluster_security_group(options = {}) + cluster_security_group_name = options[:cluster_security_group_name] + description = options[:description] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::CreateClusterSecurityGroup.new + } + + params[:query]['Action'] = 'CreateClusterSecurityGroup' + params[:query]['ClusterSecurityGroupName'] = cluster_security_group_name if cluster_security_group_name + params[:query]['Description'] = description if description + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/create_cluster_snapshot.rb b/lib/fog/aws/requests/redshift/create_cluster_snapshot.rb new file mode 100644 index 000000000..c91826f5d --- /dev/null +++ b/lib/fog/aws/requests/redshift/create_cluster_snapshot.rb @@ -0,0 +1,43 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_snapshot' + + # ==== Parameters + # + # @param [Hash] options + # * :snapshot_identifier - required - (String) + # A unique identifier for the snapshot that you are requesting. This identifier + # must be unique for all snapshots within the Aws account. Constraints: Cannot be + # null, empty, or blank Must contain from 1 to 255 alphanumeric characters or + # hyphens First character must be a letter Cannot end with a hyphen or contain two + # consecutive hyphens Example: my-snapshot-id + # * :cluster_identifier - required - (String) + # The cluster identifier for which you want a snapshot. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateClusterSnapshot.html + def create_cluster_snapshot(options = {}) + snapshot_identifier = options[:snapshot_identifier] + cluster_identifier = options[:cluster_identifier] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSnapshot.new + } + + params[:query]['Action'] = 'CreateClusterSnapshot' + params[:query]['SnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/create_cluster_subnet_group.rb b/lib/fog/aws/requests/redshift/create_cluster_subnet_group.rb new file mode 100644 index 000000000..6d1cca4ae --- /dev/null +++ b/lib/fog/aws/requests/redshift/create_cluster_subnet_group.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_subnet_group_parser' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_subnet_group_name - required - (String) + # The name for the subnet group. Amazon Redshift stores the value as a lowercase string. + # Constraints: Must contain no more than 255 alphanumeric characters or hyphens. Must not + # be "Default". Must be unique for all subnet groups that are created by your Aws account. + # Example: examplesubnetgroup + # * :description - required - (String) + # A description of the parameter group. + # * :subnet_ids - required - (Array<) + # An array of VPC subnet IDs. A maximum of 20 subnets can be modified in a single request. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateClusterSubnetGroup.html + def create_cluster_subnet_group(options = {}) + cluster_subnet_group_name = options[:cluster_subnet_group_name] + description = options[:description] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSubnetGroupParser.new + } + + if subnet_ids = options.delete(:subnet_ids) + params[:query].merge!(Fog::AWS.indexed_param('SubnetIds.member.%d', [*subnet_ids])) + end + + params[:query]['Action'] = 'CreateClusterSubnetGroup' + params[:query]['ClusterSubnetGroupName'] = cluster_subnet_group_name if cluster_subnet_group_name + params[:query]['Description'] = description if description + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/delete_cluster.rb b/lib/fog/aws/requests/redshift/delete_cluster.rb new file mode 100644 index 000000000..9788e0e05 --- /dev/null +++ b/lib/fog/aws/requests/redshift/delete_cluster.rb @@ -0,0 +1,50 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - required - (String) + # A unique identifier for the cluster. You use this identifier to refer to the cluster + # for any subsequent cluster operations such as deleting or modifying. Must be unique + # for all clusters within an Aws account. Example: myexamplecluster + # * :skip_final_cluster_snapshot - (Boolean) + # Determines whether a final snapshot of the cluster is created before Amazon Redshift + # deletes the cluster. If `true` , a final cluster snapshot is not created. If `false`, + # a final cluster snapshot is created before the cluster is deleted. The + # FinalClusterSnapshotIdentifier parameter must be specified if SkipFinalClusterSnapshot + # is `false` . Default: `false` + # * :final_cluster_snapshot_identifier - (String) + # The identifier of the final snapshot that is to be created immediately before deleting + # the cluster. If this parameter is provided, SkipFinalClusterSnapshot must be `false`. + # Constraints: Must be 1 to 255 alphanumeric characters. First character must be a letter + # Cannot end with a hyphen or contain two consecutive hyphens. + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DeleteCluster.html + def delete_cluster(options = {}) + cluster_identifier = options[:cluster_identifier] + final_cluster_snapshot_identifier = options[:final_cluster_snapshot_identifier] + skip_final_cluster_snapshot = options[:skip_final_cluster_snapshot] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::Cluster.new + } + + params[:query]['Action'] = 'DeleteCluster' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + params[:query]['FinalClusterSnapshotIdentifier'] = final_cluster_snapshot_identifier if final_cluster_snapshot_identifier + params[:query]['SkipFinalClusterSnapshot'] = skip_final_cluster_snapshot if skip_final_cluster_snapshot + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/delete_cluster_parameter_group.rb b/lib/fog/aws/requests/redshift/delete_cluster_parameter_group.rb new file mode 100644 index 000000000..15b5f42e7 --- /dev/null +++ b/lib/fog/aws/requests/redshift/delete_cluster_parameter_group.rb @@ -0,0 +1,33 @@ +module Fog + module AWS + class Redshift + class Real + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_name - required - (String) + # The name of the parameter group to be deleted. Constraints: Must be the name of an + # existing cluster parameter group. Cannot delete a default cluster parameter group. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DeleteClusterParameterGroup.html + def delete_cluster_parameter_group(options = {}) + parameter_group_name = options[:parameter_group_name] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {} + } + + params[:query]['Action'] = 'DeleteClusterParameterGroup' + params[:query]['ParameterGroupName'] = parameter_group_name if parameter_group_name + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/delete_cluster_security_group.rb b/lib/fog/aws/requests/redshift/delete_cluster_security_group.rb new file mode 100644 index 000000000..b7f0059d9 --- /dev/null +++ b/lib/fog/aws/requests/redshift/delete_cluster_security_group.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class Redshift + class Real + # ==== Parameters + # + # @param [Hash] options + # * :cluster_security_group_name - required - (String) + # The name of the cluster security group to be deleted. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DeleteClusterSecurityGroup.html + def delete_cluster_security_group(options = {}) + cluster_security_group_name = options[:cluster_security_group_name] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {} + } + + params[:query]['Action'] = 'DeleteClusterSecurityGroup' + params[:query]['ClusterSecurityGroupName'] = cluster_security_group_name if cluster_security_group_name + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/delete_cluster_snapshot.rb b/lib/fog/aws/requests/redshift/delete_cluster_snapshot.rb new file mode 100644 index 000000000..f06431457 --- /dev/null +++ b/lib/fog/aws/requests/redshift/delete_cluster_snapshot.rb @@ -0,0 +1,43 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_snapshot' + + # ==== Parameters + # + # @param [Hash] options + # * :snapshot_identifier - required - (String) + # A unique identifier for the snapshot that you are requesting. This identifier + # must be unique for all snapshots within the Aws account. Constraints: Cannot be + # null, empty, or blank Must contain from 1 to 255 alphanumeric characters or + # hyphens First character must be a letter Cannot end with a hyphen or contain two + # consecutive hyphens Example: my-snapshot-id + # * :snapshot_cluster_identifier - required - (String) + # The cluster identifier for which you want a snapshot. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateClusterSnapshot.html + def delete_cluster_snapshot(options = {}) + snapshot_identifier = options[:snapshot_identifier] + snapshot_cluster_identifier = options[:snapshot_cluster_identifier] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSnapshot.new + } + + params[:query]['Action'] = 'DeleteClusterSnapshot' + params[:query]['SnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + params[:query]['SnapshotClusterIdentifier'] = snapshot_cluster_identifier if snapshot_cluster_identifier + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/delete_cluster_subnet_group.rb b/lib/fog/aws/requests/redshift/delete_cluster_subnet_group.rb new file mode 100644 index 000000000..0883107fe --- /dev/null +++ b/lib/fog/aws/requests/redshift/delete_cluster_subnet_group.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class Redshift + class Real + # ==== Parameters + # + # @param [Hash] options + # * :cluster_subnet_group_name - required - (String) + # The name for the subnet group. Amazon Redshift stores the value as a lowercase string. + # Constraints: Must contain no more than 255 alphanumeric characters or hyphens. Must not + # be "Default". Must be unique for all subnet groups that are created by your Aws account. + # Example: examplesubnetgroup + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DeleteClusterSubnetGroup.html + def delete_cluster_subnet_group(options = {}) + cluster_subnet_group_name = options[:cluster_subnet_group_name] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :delete, + :query => {} + } + + params[:query]['Action'] = 'DeleteClusterSubnetGroup' + params[:query]['ClusterSubnetGroupName'] = cluster_subnet_group_name if cluster_subnet_group_name + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_cluster_parameter_groups.rb b/lib/fog/aws/requests/redshift/describe_cluster_parameter_groups.rb new file mode 100644 index 000000000..41ee1fe26 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_cluster_parameter_groups.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_cluster_parameter_groups' + + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_name (String) + # The name of a cluster parameter group for which to return details. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterParameterGroups.html + def describe_cluster_parameter_groups(options = {}) + parameter_group_name = options[:parameter_group_name] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusterParameterGroups.new + } + + params[:query]['Action'] = 'DescribeClusterParameterGroups' + params[:query]['ParameterGroupName'] = parameter_group_name if parameter_group_name + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_cluster_parameters.rb b/lib/fog/aws/requests/redshift/describe_cluster_parameters.rb new file mode 100644 index 000000000..b727a3a96 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_cluster_parameters.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_cluster_parameters' + + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_name - required - (String) + # The name of a cluster parameter group for which to return details. + # * :source - (String) + # The parameter types to return. Specify user to show parameters that are + # different form the default. Similarly, specify engine-default to show parameters + # that are the same as the default parameter group. Default: All parameter types + # returned. Valid Values: user | engine-default + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterParameters.html + def describe_cluster_parameters(options = {}) + parameter_group_name = options[:parameter_group_name] + source = options[:source] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusterParameters.new + } + + params[:query]['Action'] = 'DescribeClusterParameters' + params[:query]['ParameterGroupName'] = parameter_group_name if parameter_group_name + params[:query]['Source'] = source if source + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_cluster_security_groups.rb b/lib/fog/aws/requests/redshift/describe_cluster_security_groups.rb new file mode 100644 index 000000000..f90236394 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_cluster_security_groups.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_cluster_security_groups' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_security_group_name - (String) + # The name of a cluster security group for which you are requesting details. You + # can specify either the Marker parameter or a ClusterSecurityGroupName parameter, + # but not both. Example: securitygroup1 + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterSecurityGroups.html + def describe_cluster_security_groups(options = {}) + cluster_security_group_name = options[:cluster_security_group_name] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusterSecurityGroups.new + } + + params[:query]['Action'] = 'DescribeClusterSecurityGroups' + params[:query]['ClusterSecurityGroupName'] = cluster_security_group_name if cluster_security_group_name + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_cluster_snapshots.rb b/lib/fog/aws/requests/redshift/describe_cluster_snapshots.rb new file mode 100644 index 000000000..008d91ebe --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_cluster_snapshots.rb @@ -0,0 +1,72 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_cluster_snapshots' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - (String) + # The identifier of the cluster for which information about snapshots is requested. + # * :snapshot_identifier - (String) + # The snapshot identifier of the snapshot about which to return information. + # * :snapshot_type - (String) + # The type of snapshots for which you are requesting information. By default, + # snapshots of all types are returned. Valid Values: automated | manual + # * :start_time - (String) + # A value that requests only snapshots created at or after the specified time. + # The time value is specified in ISO 8601 format. For more information about + # ISO 8601, go to the ISO8601 Wikipedia page. Example: 2012-07-16T18:00:00Z + # * :end_time - (String) + # A time value that requests only snapshots created at or before the specified + # time. The time value is specified in ISO 8601 format. For more information + # about ISO 8601, go to the ISO8601 Wikipedia page. Example: 2012-07-16T18:00:00Z + # * :owner_account - (String) + # The Aws customer account used to create or copy the snapshot. Use this field to + # filter the results to snapshots owned by a particular account. To describe snapshots + # you own, either specify your Aws customer account, or do not specify the parameter. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterSnapshots.html + def describe_cluster_snapshots(options = {}) + cluster_identifier = options[:cluster_identifier] + snapshot_identifier = options[:snapshot_identifier] + start_time = options[:start_time] + end_time = options[:end_time] + owner_account = options[:owner_account] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusterSnapshots.new + } + + params[:query]['Action'] = 'DescribeClusterSnapshots' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + params[:query]['SnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + params[:query]['start_time'] = start_time if start_time + params[:query]['end_time'] = end_time if end_time + params[:query]['OwnerAccount'] = owner_account if owner_account + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_cluster_subnet_groups.rb b/lib/fog/aws/requests/redshift/describe_cluster_subnet_groups.rb new file mode 100644 index 000000000..dd3f64cf4 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_cluster_subnet_groups.rb @@ -0,0 +1,46 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_cluster_subnet_groups' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_subnet_group_name - (String) + # The name of the cluster subnet group for which information is requested. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== Returns + # * response<~Excon::Response>: + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterSubnetGroups.html + def describe_cluster_subnet_groups(cluster_subnet_group_name=nil, marker=nil,max_records=nil) + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusterSubnetGroups.new + } + + params[:query]['Action'] = 'DescribeClusterSubnetGroups' + params[:query]['ClusterSubnetGroupName'] = cluster_subnet_group_name if cluster_subnet_group_name + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_cluster_versions.rb b/lib/fog/aws/requests/redshift/describe_cluster_versions.rb new file mode 100644 index 000000000..1a83c355c --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_cluster_versions.rb @@ -0,0 +1,53 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_cluster_versions' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_parameter_group_family - (String) + # The name of a specific cluster parameter group family to return details for. + # Constraints: Must be 1 to 255 alphanumeric characters. First character must be + # a letter, and cannot end with a hyphen or contain two consecutive hyphens. + # * :cluster_version - (String) + # The specific cluster version to return. Example: 1.0 + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterVersions.html + def describe_cluster_versions(options = {}) + cluster_version = options[:cluster_version] + cluster_parameter_group_family = options[:cluster_parameter_group_family] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusterVersions.new + } + + params[:query]['Action'] = 'DescribeClusterVersions' + params[:query]['ClusterVersion'] = cluster_version if cluster_version + params[:query]['ClusterParameterGroupFamily'] = cluster_parameter_group_family if cluster_parameter_group_family + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_clusters.rb b/lib/fog/aws/requests/redshift/describe_clusters.rb new file mode 100644 index 000000000..6329ec846 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_clusters.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_clusters' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - (String) + # The unique identifier of a cluster whose properties you are requesting. + # This parameter isn't case sensitive. The default is that all clusters + # defined for an account are returned. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusters.html + def describe_clusters(options = {}) + cluster_identifier = options[:cluster_identifier] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeClusters.new + } + + params[:query]['Action'] = 'DescribeClusters' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + params[:query]['MaxRecords'] = max_records if max_records + params[:query]['Marker'] = marker if marker + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_default_cluster_parameters.rb b/lib/fog/aws/requests/redshift/describe_default_cluster_parameters.rb new file mode 100644 index 000000000..9749e7996 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_default_cluster_parameters.rb @@ -0,0 +1,48 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_default_cluster_parameters' + + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_family - required - (String) + # The name of a cluster parameter group family for which to return details. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeDefaultClusterParameters.html + def describe_default_cluster_parameters(options = {}) + parameter_group_family = options[:parameter_group_family] + source = options[:source] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeDefaultClusterParameters.new + } + + params[:query]['Action'] = 'DescribeDefaultClusterParameters' + params[:query]['ParameterGroupFamily'] = parameter_group_family if parameter_group_family + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_events.rb b/lib/fog/aws/requests/redshift/describe_events.rb new file mode 100644 index 000000000..16a157635 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_events.rb @@ -0,0 +1,79 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_events' + + # ==== Parameters + # + # @param [Hash] options + # * :source_identifier - (String) + # The identifier of the event source for which events will be returned. If this + # parameter is not specified, then all sources are included in the response. + # Constraints: If SourceIdentifier is supplied, SourceType must also be provided. + # Specify a cluster identifier when SourceType is cluster. Specify a cluster security + # group name when SourceType is cluster-security-group. Specify a cluster parameter + # group name when SourceType is cluster-parameter-group. Specify a cluster snapshot + # identifier when SourceType is cluster-snapshot. + # * :source_type - (String) + # The event source to retrieve events for. If no value is specified, all events are + # returned. Constraints: If SourceType is supplied, SourceIdentifier must also be + # provided. Specify cluster when SourceIdentifier is a cluster identifier. Specify + # cluster-security-group when SourceIdentifier is a cluster security group name. Specify + # cluster-parameter-group when SourceIdentifier is a cluster parameter group name. Specify + # cluster-snapshot when SourceIdentifier is a cluster snapshot identifier. Valid values + # include: cluster, cluster-parameter-group, cluster-security-group, cluster-snapshot + # * :start_time - (String<) + # The beginning of the time interval to retrieve events for, specified in ISO 8601 + # format. Example: 2009-07-08T18:00Z + # * :end_time - (String<) + # The end of the time interval for which to retrieve events, specified in ISO 8601 + # format. Example: 2009-07-08T18:00Z + # * :duration - (Integer) + # The number of minutes prior to the time of the request for which to retrieve events. + # For example, if the request is sent at 18:00 and you specify a duration of 60, then + # only events which have occurred after 17:00 will be returned. Default: 60 + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeEvents.html + def describe_events(options = {}) + source_identifier = options[:source_identifier] + source_type = options[:source_type] + start_time = options[:start_time] + end_time = options[:end_time] + duration = options[:duration] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeEvents.new + } + + params[:query]['Action'] = 'DescribeEvents' + params[:query]['SourceIdentifier'] = source_identifier if source_identifier + params[:query]['SourceType'] = source_type if source_type + params[:query]['StartTime'] = start_time if start_time + params[:query]['EndTime'] = end_time if end_time + params[:query]['Duration'] = duration if duration + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_orderable_cluster_options.rb b/lib/fog/aws/requests/redshift/describe_orderable_cluster_options.rb new file mode 100644 index 000000000..a5c591bb5 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_orderable_cluster_options.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_orderable_cluster_options' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_version - (String) + # The version filter value. Specify this parameter to show only the available + # offerings matching the specified version. Default: All versions. Constraints: + # Must be one of the version returned from DescribeClusterVersions. + # * :node_type - (String) + # The node type filter value. Specify this parameter to show only the available + # offerings matching the specified node type. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeOrderableClusterOptions.html + def describe_orderable_cluster_options(options = {}) + cluster_version = options[:cluster_version] + node_type = options[:node_type] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeOrderableClusterOptions.new + } + + params[:query]['Action'] = 'DescribeOrderableClusterOptions' + params[:query]['ClusterVersion'] = cluster_version if cluster_version + params[:query]['NodeType'] = node_type if node_type + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_reserved_node_offerings.rb b/lib/fog/aws/requests/redshift/describe_reserved_node_offerings.rb new file mode 100644 index 000000000..9b8726f07 --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_reserved_node_offerings.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_reserved_node_offerings' + + # ==== Parameters + # + # @param [Hash] options + # * :reserved_node_offering_id - (String) + # The unique identifier for the offering. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeReservedNodeOfferings.html + def describe_reserved_node_offerings(options = {}) + reserved_node_offering_id = options[:reserved_node_offering_id] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeReservedNodeOfferings.new + } + + params[:query]['Action'] = 'DescribeReservedNodeOfferings' + params[:query]['ReservedNodeOfferingId'] = reserved_node_offering_id if reserved_node_offering_id + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_reserved_nodes.rb b/lib/fog/aws/requests/redshift/describe_reserved_nodes.rb new file mode 100644 index 000000000..41382608a --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_reserved_nodes.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_reserved_nodes' + + # ==== Parameters + # + # @param [Hash] options + # * :reserved_node_id - (String) + # The unique identifier for the node reservation. + # * :max_records - (Integer) + # The maximum number of records to include in the response. If more than the + # MaxRecords value is available, a marker is included in the response so that the + # following results can be retrieved. Constrained between [20,100]. Default is 100. + # * :marker - (String) + # The marker returned from a previous request. If this parameter is specified, the + # response includes records beyond the marker only, up to MaxRecords. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeReservedNodes.html + def describe_reserved_nodes(options = {}) + reserved_node_id = options[:reserved_node_id] + marker = options[:marker] + max_records = options[:max_records] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeReservedNodes.new + } + + params[:query]['Action'] = 'DescribeReservedNodes' + params[:query]['ReservedNodeId'] = reserved_node_id if reserved_node_id + params[:query]['Marker'] = marker if marker + params[:query]['MaxRecords'] = max_records if max_records + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/describe_resize.rb b/lib/fog/aws/requests/redshift/describe_resize.rb new file mode 100644 index 000000000..82bd74e1e --- /dev/null +++ b/lib/fog/aws/requests/redshift/describe_resize.rb @@ -0,0 +1,38 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/describe_resize' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - required - (String) + # The unique identifier of a cluster whose resize progress you are requesting. + # This parameter isn't case-sensitive. By default, resize operations for all + # clusters defined for an Aws account are returned. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeResize.html + def describe_resize(options = {}) + cluster_identifier = options[:cluster_identifier] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :get, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::DescribeResize.new + } + + params[:query]['Action'] = 'DescribeResize' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/modify_cluster.rb b/lib/fog/aws/requests/redshift/modify_cluster.rb new file mode 100644 index 000000000..7562dbf6c --- /dev/null +++ b/lib/fog/aws/requests/redshift/modify_cluster.rb @@ -0,0 +1,109 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - required - (String) + # A unique identifier for the cluster. You use this identifier to refer to the cluster + # for any subsequent cluster operations such as deleting or modifying. Must be unique + # for all clusters within an Aws account. Example: myexamplecluster + # * :allow_version_upgrade - (Boolean) + # If `true` , upgrades can be applied during the maintenance window to the Amazon + # Redshift engine that is running on the cluster. Default: `true` + # * :automated_snapshot_retention_period - (Integer) + # Number of days that automated snapshots are retained. If the value is 0, automated + # snapshots are disabled. Default: 1 Constraints: Must be a value from 0 to 35. + # * :cluster_parameter_group_name - (String) + # The name of the parameter group to be associated with this cluster. Default: The + # default Amazon Redshift cluster parameter group. Constraints: Must be 1 to 255 + # alphanumeric characters or hyphens. First character must be a letter. Cannot end + # with a hyphen or contain two consecutive hyphens. + # * :cluster_security_groups - (Array) + # A list of security groups to be associated with this cluster. Default: The default + # cluster security group for Amazon Redshift. + # * :cluster_type - (String) + # Type of the cluster. When cluster type is specified as single-node, the NumberOfNodes + # parameter is not required. multi-node, the NumberOfNodes parameter is required. Valid + # Values: multi-node | single-node Default: multi-node + # * :cluster_version - (String) + # The version of the Amazon Redshift engine software that you want to deploy on the + # cluster. The version selected runs on all the nodes in the cluster. Constraints: + # Only version 1.0 is currently available. Example: 1.0 + # * :master_user_password - required - (String) + # The password associated with the master user account for the cluster that is being + # created. Constraints: Must be between 8 and 64 characters in length. Must contain at + # least one uppercase letter. Must contain at least one lowercase letter. Must contain + # one number. + # * :node_type - required - (String) + # The node type to be provisioned. Valid Values: dw.hs1.xlarge | dw.hs1.8xlarge. + # * :number_of_nodes - (Integer) + # The number of compute nodes in the cluster. This parameter is required when the + # ClusterType parameter is specified as multi-node. If you don't specify this parameter, + # you get a single-node cluster. When requesting a multi-node cluster, you must specify + # the number of nodes that you want in the cluster. Default: 1 Constraints: Value must + # be at least 1 and no more than 100. + # * :preferred_maintenance_window - (String) + # The weekly time range (in UTC) during which automated cluster maintenance can occur. + # Format: ddd:hh24:mi-ddd:hh24:mi Default: A 30-minute window selected at random from + # an 8-hour block of time per region, occurring on a random day of the week. + # Constraints: Minimum 30-minute window. + # * :vpc_security_group_ids - (Array) + # A list of Virtual Private Cloud (VPC) security groups to be associated with the + # cluster. Default: The default VPC security group is associated with the cluster. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_CreateCluster.html + def modify_cluster(options = {}) + cluster_identifier = options[:cluster_identifier] + cluster_type = options[:cluster_type] + node_type = options[:node_type] + master_user_password = options[:master_user_password] + preferred_maintenance_window = options[:preferred_maintenance_window] + cluster_parameter_group_name = options[:cluster_parameter_group_name] + automated_snapshot_retention_period = options[:automated_snapshot_retention_period] + cluster_version = options[:cluster_version] + allow_version_upgrade = options[:allow_version_upgrade] + number_of_nodes = options[:number_of_nodes] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::Cluster.new + } + + if cluster_security_groups = options.delete(:ClusterSecurityGroups) + params[:query].merge!(Fog::AWS.indexed_param('ClusterSecurityGroups.member.%d', [*cluster_security_groups])) + end + + if vpc_security_group_ids = options.delete(:VpcSecurityGroupIds) + params[:query].merge!(Fog::AWS.indexed_param('VpcSecurityGroupIds.member.%d', [*vpc_security_group_ids])) + end + + params[:query]['Action'] = 'ModifyCluster' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + params[:query]['ClusterParameterGroupName'] = cluster_parameter_group_name if cluster_parameter_group_name + params[:query]['ClusterType'] = cluster_type if cluster_type + params[:query]['NodeType'] = node_type if node_type + params[:query]['MasterUserPassword'] = master_user_password if master_user_password + params[:query]['PreferredMaintenanceWindow'] = preferred_maintenance_window if preferred_maintenance_window + params[:query]['AutomatedSnapshotRetentionPeriod'] = automated_snapshot_retention_period if automated_snapshot_retention_period + params[:query]['ClusterVersion'] = cluster_version if cluster_version + params[:query]['AllowVersionUpgrade'] = allow_version_upgrade if allow_version_upgrade + params[:query]['NumberOfNodes'] = number_of_nodes if number_of_nodes + params[:query]['ClusterSecurityGroups'] = cluster_security_groups if cluster_security_groups + params[:query]['VpcSecurityGroupIds'] = vpc_security_group_ids if vpc_security_group_ids + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/modify_cluster_parameter_group.rb b/lib/fog/aws/requests/redshift/modify_cluster_parameter_group.rb new file mode 100644 index 000000000..e3f2b1042 --- /dev/null +++ b/lib/fog/aws/requests/redshift/modify_cluster_parameter_group.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/update_cluster_parameter_group_parser' + + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_name - required - (String) + # The name of the parameter group to be deleted. Constraints: Must be the name of an + # existing cluster parameter group. Cannot delete a default cluster parameter group. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_ModifyClusterParameterGroup.html + def modify_cluster_parameter_group(options = {}) + parameter_group_name = options[:parameter_group_name] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::UpdateClusterParameterGroupParser.new + } + + params[:query]['Action'] = 'ModifyClusterParameterGroup' + params[:query]['ParameterGroupName'] = parameter_group_name if parameter_group_name + + if options['Parameters'] + options['Parameters'].keys.each_with_index do |name, index| + params[:query].merge!({ + "Parameters.member.#{index+1}.#{name}" => options['Parameters'][name] + }) + end + end + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/modify_cluster_subnet_group.rb b/lib/fog/aws/requests/redshift/modify_cluster_subnet_group.rb new file mode 100644 index 000000000..5a62a2819 --- /dev/null +++ b/lib/fog/aws/requests/redshift/modify_cluster_subnet_group.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_subnet_group_parser' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_subnet_group_name - required - (String) + # The name for the subnet group. Amazon Redshift stores the value as a lowercase string. + # Constraints: Must contain no more than 255 alphanumeric characters or hyphens. Must not + # be "Default". Must be unique for all subnet groups that are created by your Aws account. + # Example: examplesubnetgroup + # * :description - required - (String) + # A description of the parameter group. + # * :subnet_ids - required - (Array<) + # An array of VPC subnet IDs. A maximum of 20 subnets can be modified in a single request. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_ModifyClusterSubnetGroup.html + def modify_cluster_subnet_group(options = {}) + cluster_subnet_group_name = options[:cluster_subnet_group_name] + description = options[:description] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSubnetGroupParser.new + } + + if subnet_ids = options.delete(:subnet_ids) + params[:query].merge!(Fog::AWS.indexed_param('SubnetIds.member.%d', [*subnet_ids])) + end + + params[:query]['Action'] = 'ModifyClusterSubnetGroup' + params[:query]['ClusterSubnetGroupName'] = cluster_subnet_group_name if cluster_subnet_group_name + params[:query]['Description'] = description if description + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/purchase_reserved_node_offering.rb b/lib/fog/aws/requests/redshift/purchase_reserved_node_offering.rb new file mode 100644 index 000000000..e41d52277 --- /dev/null +++ b/lib/fog/aws/requests/redshift/purchase_reserved_node_offering.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/purchase_reserved_node_offering' + + # ==== Parameters + # + # @param [Hash] options + # * :reserved_node_offering_id - required - (String) + # The unique identifier of the reserved node offering you want to purchase. + # * :node_count - (Integer) + # The number of reserved nodes you want to purchase. Default: 1 + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_PurchaseReservedNodeOffering.html + def purchase_reserved_node_offering(options = {}) + reserved_node_offering_id = options[:reserved_node_offering_id] + node_count = options[:node_count] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::PurchaseReservedNodeOffering.new + } + + params[:query]['Action'] = 'PurchaseReservedNodeOffering' + params[:query]['ReservedNodeOfferingId'] = reserved_node_offering_id if reserved_node_offering_id + params[:query]['NodeCount'] = node_count if node_count + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/reboot_cluster.rb b/lib/fog/aws/requests/redshift/reboot_cluster.rb new file mode 100644 index 000000000..e5147864b --- /dev/null +++ b/lib/fog/aws/requests/redshift/reboot_cluster.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - required - (String) + # A unique identifier for the cluster. You use this identifier to refer to the cluster + # for any subsequent cluster operations such as deleting or modifying. Must be unique + # for all clusters within an Aws account. Example: myexamplecluster + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_DeleteCluster.html + def reboot_cluster(options = {}) + cluster_identifier = options[:cluster_identifier] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::Cluster.new + } + + params[:query]['Action'] = 'RebootCluster' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/reset_cluster_parameter_group.rb b/lib/fog/aws/requests/redshift/reset_cluster_parameter_group.rb new file mode 100644 index 000000000..b33c9b33e --- /dev/null +++ b/lib/fog/aws/requests/redshift/reset_cluster_parameter_group.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/update_cluster_parameter_group_parser' + + # ==== Parameters + # + # @param [Hash] options + # * :parameter_group_name - required - (String) The name of the cluster parameter group to be reset. + # * :reset_all_parameters - (Boolean) If true , all parameters in the specified parameter group will be reset to their default values. Default: true + # * :parameters - (Array<) An array of names of parameters to be reset. If ResetAllParameters option is not used, then at least one parameter name must be supplied. Constraints: A maximum of 20 parameters can be reset in a single request. + # * :parameter_name - (String) The name of the parameter. + # * :parameter_value - (String) The value of the parameter. + # * :description - (String) A description of the parameter. + # * :source - (String) The source of the parameter value, such as "engine-default" or "user". + # * :data_type - (String) The data type of the parameter. + # * :allowed_values - (String) The valid range of values for the parameter. + # * :is_modifiable - (Boolean) If true , the parameter can be modified. Some parameters have security or operational implications that prevent them from being changed. + # * :minimum_engine_version - (String) The earliest engine version to which the parameter can apply. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_ResetClusterParameterGroup.html + def reset_cluster_parameter_group(options = {}) + parameter_group_name = options[:parameter_group_name] + reset_all_parameters = options[:reset_all_parameters] + + path = "/" + params = { + :idempotent => true, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::UpdateClusterParameterGroupParser.new + } + + if options['Parameters'] + options['Parameters'].keys.each_with_index do |name, index| + params[:query].merge!({ + "Parameters.member.#{index+1}.#{name}" => options['Parameters'][name] + }) + end + end + + params[:query]['Action'] = 'ResetClusterSubnetGroup' + params[:query]['ParameterGroupName'] = parameter_group_name if parameter_group_name + params[:query]['ResetAllParameters'] = reset_all_parameters if reset_all_parameters + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/restore_from_cluster_snapshot.rb b/lib/fog/aws/requests/redshift/restore_from_cluster_snapshot.rb new file mode 100644 index 000000000..7de57ff0c --- /dev/null +++ b/lib/fog/aws/requests/redshift/restore_from_cluster_snapshot.rb @@ -0,0 +1,76 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_identifier - required - (String) + # The identifier of the cluster that will be created from restoring the snapshot. + # Constraints: Must contain from 1 to 63 alphanumeric characters or hyphens. + # Alphabetic characters must be lowercase. First character must be a letter. Cannot + # end with a hyphen or contain two consecutive hyphens. Must be unique for all + # clusters within an Aws account. + # * :snapshot_identifier - required - (String) + # The name of the snapshot from which to create the new cluster. This parameter + # isn't case sensitive. Example: my-snapshot-id + # * :snapshot_cluster_identifier - (String) + # * :port - (Integer) + # The port number on which the cluster accepts connections. Default: The same port + # as the original cluster. Constraints: Must be between 1115 and 65535. + # * :availability_zone - (String) + # The Amazon EC2 Availability Zone in which to restore the cluster. Default: A + # random, system-chosen Availability Zone. Example: us-east-1a + # * :allow_version_upgrade - (Boolean) + # If true , upgrades can be applied during the maintenance window to the Amazon + # Redshift engine that is running on the cluster. Default: true + # * :cluster_subnet_group_name - (String) + # The name of the subnet group where you want to cluster restored. A snapshot of + # cluster in VPC can be restored only in VPC. Therefore, you must provide subnet + # group name where you want the cluster restored. + # * :publicly_accessible - (Boolean) + # If true , the cluster can be accessed from a public network. + # * :owner_account - (String) + # The Aws customer account used to create or copy the snapshot. Required if you are + # restoring a snapshot you do not own, optional if you own the snapshot. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_RestoreFromClusterSnapshot.html + def restore_from_cluster_snapshot(options = {}) + cluster_identifier = options[:cluster_identifier] + snapshot_identifier = options[:snapshot_identifier] + snapshot_cluster_identifier = options[:snapshot_cluster_identifier] + port = options[:port] + availability_zone = options[:availability_zone] + allow_version_upgrade = options[:allow_version_upgrade] + cluster_subnet_group_name = options[:cluster_subnet_group_name] + publicly_accessible = options[:publicly_accessible] + owner_account = options[:owner_account] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::Cluster.new + } + + params[:query]['Action'] = 'RestoreFromClusterSnapshot' + params[:query]['ClusterIdentifier'] = cluster_identifier if cluster_identifier + params[:query]['SnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + params[:query]['SnapshotClusterIdentifier'] = snapshot_cluster_identifier if snapshot_cluster_identifier + params[:query]['Port'] = port if port + params[:query]['AvailabilityZone'] = availability_zone if availability_zone + params[:query]['AllowVersionUpgrade'] = allow_version_upgrade if allow_version_upgrade + params[:query]['ClusterSubnetGroupName'] = cluster_subnet_group_name if cluster_subnet_group_name + params[:query]['PubliclyAccessible'] = publicly_accessible if publicly_accessible + params[:query]['OwnerAccount'] = owner_account if owner_account + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/revoke_cluster_security_group_ingress.rb b/lib/fog/aws/requests/redshift/revoke_cluster_security_group_ingress.rb new file mode 100644 index 000000000..cb9287bca --- /dev/null +++ b/lib/fog/aws/requests/redshift/revoke_cluster_security_group_ingress.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/revoke_cluster_security_group_ingress' + + # ==== Parameters + # + # @param [Hash] options + # * :cluster_security_group_name - required - (String) + # The name of the security Group from which to revoke the ingress rule. + # * :cidrip - (String) + # The IP range for which to revoke access. This range must be a valid Classless + # Inter-Domain Routing (CIDR) block of IP addresses. If CIDRIP is specified, + # EC2SecurityGroupName and EC2SecurityGroupOwnerId cannot be provided. + # * :ec2_security_group_name - (String) + # The name of the EC2 Security Group whose access is to be revoked. If + # EC2SecurityGroupName is specified, EC2SecurityGroupOwnerId must also be + # provided and CIDRIP cannot be provided. + # * :ec2_security_group_owner_id - (String) + # The Aws account number of the owner of the security group specified in the + # EC2SecurityGroupName parameter. The Aws access key ID is not an acceptable + # value. If EC2SecurityGroupOwnerId is specified, EC2SecurityGroupName must + # also be provided. and CIDRIP cannot be provided. Example: 111122223333 + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_RevokeClusterSecurityGroupIngress.html + def revoke_cluster_security_group_ingress(options = {}) + cluster_security_group_name = options[:cluster_security_group_name] + cidrip = options[:cidrip] + ec2_security_group_name = options[:ec2_security_group_name] + ec2_security_group_owner_id = options[:ec2_security_group_owner_id] + + path = "/" + params = { + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::RevokeClusterSecurityGroupIngress.new + } + + params[:query]['Action'] = 'RevokeClusterSecurityGroupIngress' + params[:query]['ClusterSecurityGroupName'] = cluster_security_group_name if cluster_security_group_name + params[:query]['CIDRIP'] = cidrip if cidrip + params[:query]['EC2SecurityGroupName'] = ec2_security_group_name if ec2_security_group_name + params[:query]['EC2SecurityGroupOwnerId'] = ec2_security_group_owner_id if ec2_security_group_owner_id + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/redshift/revoke_snapshot_access.rb b/lib/fog/aws/requests/redshift/revoke_snapshot_access.rb new file mode 100644 index 000000000..fbb54facd --- /dev/null +++ b/lib/fog/aws/requests/redshift/revoke_snapshot_access.rb @@ -0,0 +1,43 @@ +module Fog + module AWS + class Redshift + class Real + require 'fog/aws/parsers/redshift/cluster_snapshot' + + # ==== Parameters + # + # @param [Hash] options + # * :snapshot_identifier - required - (String) + # The identifier of the snapshot that the account can no longer access. + # * :snapshot_cluster_identifier - (String) + # * :account_with_restore_access - required - (String) + # The identifier of the Aws customer account that can no longer restore the specified snapshot. + # + # ==== See Also + # http://docs.aws.amazon.com/redshift/latest/APIReference/API_RevokeSnapshotAccess.html + def revoke_snapshot_access(options = {}) + snapshot_identifier = options[:snapshot_identifier] + snapshot_cluster_identifier = options[:snapshot_cluster_identifier] + account_with_restore_access = options[:account_with_restore_access] + + path = "/" + params = { + :expects => 200, + :headers => {}, + :path => path, + :method => :put, + :query => {}, + :parser => Fog::Parsers::Redshift::AWS::ClusterSnapshot.new + } + + params[:query]['Action'] = 'RevokeSnapshotAccess' + params[:query]['SnapshotIdentifier'] = snapshot_identifier if snapshot_identifier + params[:query]['SnapshotClusterIdentifier'] = snapshot_cluster_identifier if snapshot_cluster_identifier + params[:query]['AccountWithRestoreAccess'] = account_with_restore_access if account_with_restore_access + + request(params) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/delete_verified_email_address.rb b/lib/fog/aws/requests/ses/delete_verified_email_address.rb new file mode 100644 index 000000000..270b5057a --- /dev/null +++ b/lib/fog/aws/requests/ses/delete_verified_email_address.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/delete_verified_email_address' + + # Delete an existing verified email address + # + # ==== Parameters + # * email_address<~String> - Email Address to be removed + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def delete_verified_email_address(email_address) + request({ + 'Action' => 'DeleteVerifiedEmailAddress', + 'EmailAddress' => email_address, + :parser => Fog::Parsers::AWS::SES::DeleteVerifiedEmailAddress.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/get_send_quota.rb b/lib/fog/aws/requests/ses/get_send_quota.rb new file mode 100644 index 000000000..b113c2f3c --- /dev/null +++ b/lib/fog/aws/requests/ses/get_send_quota.rb @@ -0,0 +1,29 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/get_send_quota' + + # Returns the user's current activity limits. + # + # ==== Parameters + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'GetSendQuotaResult'<~Hash> + # * 'Max24HourSend' <~String> + # * 'MaxSendRate' <~String> + # * 'SentLast24Hours' <~String> + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def get_send_quota + request({ + 'Action' => 'GetSendQuota', + :parser => Fog::Parsers::AWS::SES::GetSendQuota.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/get_send_statistics.rb b/lib/fog/aws/requests/ses/get_send_statistics.rb new file mode 100644 index 000000000..fd11e121c --- /dev/null +++ b/lib/fog/aws/requests/ses/get_send_statistics.rb @@ -0,0 +1,32 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/get_send_statistics' + + # Returns the user's current activity limits. + # + # ==== Parameters + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'GetSendStatisticsResult'<~Hash> + # * 'SendDataPoints' <~Array> + # * 'Bounces' <~String> + # * 'Complaints' <~String> + # * 'DeliveryAttempts' <~String> + # * 'Rejects' <~String> + # * 'Timestamp' <~String> + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def get_send_statistics + request({ + 'Action' => 'GetSendStatistics', + :parser => Fog::Parsers::AWS::SES::GetSendStatistics.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/list_verified_email_addresses.rb b/lib/fog/aws/requests/ses/list_verified_email_addresses.rb new file mode 100644 index 000000000..7d5d6bf2d --- /dev/null +++ b/lib/fog/aws/requests/ses/list_verified_email_addresses.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/list_verified_email_addresses' + + # Returns a list containing all of the email addresses that have been verified + # + # ==== Parameters + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'VerifiedEmailAddresses' <~Array> + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def list_verified_email_addresses + request({ + 'Action' => 'ListVerifiedEmailAddresses', + :parser => Fog::Parsers::AWS::SES::ListVerifiedEmailAddresses.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/send_email.rb b/lib/fog/aws/requests/ses/send_email.rb new file mode 100644 index 000000000..1d247cfa9 --- /dev/null +++ b/lib/fog/aws/requests/ses/send_email.rb @@ -0,0 +1,71 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/send_email' + + # Send an email + # + # ==== Parameters + # * Source <~String> - The sender's email address + # * Destination <~Hash> - The destination for this email, composed of To:, From:, and CC: fields. + # * BccAddresses <~Array> - The BCC: field(s) of the message. + # * CcAddresses <~Array> - The CC: field(s) of the message. + # * ToAddresses <~Array> - The To: field(s) of the message. + # * Message <~Hash> - The message to be sent. + # * Body <~Hash> + # * Html <~Hash> + # * Charset <~String> + # * Data <~String> + # * Text <~Hash> + # * Charset <~String> + # * Data <~String> + # * Subject <~Hash> + # * Charset <~String> + # * Data <~String> + # * options <~Hash>: + # * ReplyToAddresses <~Array> - The reply-to email address(es) for the message. If the recipient replies to the message, each reply-to address will receive the reply. + # * ReturnPath <~String> - The email address to which bounce notifications are to be forwarded. If the message cannot be delivered to the recipient, then an error message will be returned from the recipient's ISP; this message will then be forwarded to the email address specified by the ReturnPath parameter. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'MessageId'<~String> - Id of message + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def send_email(source, destination, message, options = {}) + params = { + 'Source' => source + } + + for key, values in destination + params.merge!(Fog::AWS.indexed_param("Destination.#{key}.member", [*values])) + end + + for key, value in message['Subject'] + params["Message.Subject.#{key}"] = value + end + + for type, data in message['Body'] + for key, value in data + params["Message.Body.#{type}.#{key}"] = value + end + end + + if options.key?('ReplyToAddresses') + params.merge!(Fog::AWS.indexed_param("ReplyToAddresses.member", [*options['ReplyToAddresses']])) + end + + if options.key?('ReturnPath') + params['ReturnPath'] = options['ReturnPath'] + end + + request({ + 'Action' => 'SendEmail', + :parser => Fog::Parsers::AWS::SES::SendEmail.new + }.merge(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/send_raw_email.rb b/lib/fog/aws/requests/ses/send_raw_email.rb new file mode 100644 index 000000000..1a9265471 --- /dev/null +++ b/lib/fog/aws/requests/ses/send_raw_email.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/send_raw_email' + + # Send a raw email + # + # ==== Parameters + # * RawMessage <~String> - The message to be sent. + # * Options <~Hash> + # * Source <~String> - The sender's email address. Takes precenence over Return-Path if specified in RawMessage + # * Destinations <~Array> - All destinations for this email. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'MessageId'<~String> - Id of message + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def send_raw_email(raw_message, options = {}) + params = {} + if options.key?('Destinations') + params.merge!(Fog::AWS.indexed_param('Destinations.member', [*options['Destinations']])) + end + if options.key?('Source') + params['Source'] = options['Source'] + end + + request({ + 'Action' => 'SendRawEmail', + 'RawMessage.Data' => Base64.encode64(raw_message.to_s).chomp!, + :parser => Fog::Parsers::AWS::SES::SendRawEmail.new + }.merge(params)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/verify_domain_identity.rb b/lib/fog/aws/requests/ses/verify_domain_identity.rb new file mode 100644 index 000000000..3296528cb --- /dev/null +++ b/lib/fog/aws/requests/ses/verify_domain_identity.rb @@ -0,0 +1,28 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/verify_domain_identity' + + # Verifies a domain. This action returns a verification authorization + # token which must be added as a DNS TXT record to the domain. + # + # ==== Parameters + # * domain<~String> - The domain to be verified + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'VerificationToken'<~String> - Verification token + # * 'RequestId'<~String> - Id of request + def verify_domain_identity(domain) + request({ + 'Action' => 'VerifyDomainIdentity', + 'Domain' => domain, + :parser => Fog::Parsers::AWS::SES::VerifyDomainIdentity.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/ses/verify_email_address.rb b/lib/fog/aws/requests/ses/verify_email_address.rb new file mode 100644 index 000000000..0098a6fa2 --- /dev/null +++ b/lib/fog/aws/requests/ses/verify_email_address.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class SES + class Real + require 'fog/aws/parsers/ses/verify_email_address' + + # Verifies an email address. This action causes a confirmation email message to be sent to the specified address. + # + # ==== Parameters + # * email_address<~String> - The email address to be verified + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'ResponseMetadata'<~Hash>: + # * 'RequestId'<~String> - Id of request + def verify_email_address(email_address) + request({ + 'Action' => 'VerifyEmailAddress', + 'EmailAddress' => email_address, + :parser => Fog::Parsers::AWS::SES::VerifyEmailAddress.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/batch_put_attributes.rb b/lib/fog/aws/requests/simpledb/batch_put_attributes.rb new file mode 100644 index 000000000..cb99282cf --- /dev/null +++ b/lib/fog/aws/requests/simpledb/batch_put_attributes.rb @@ -0,0 +1,60 @@ +module Fog + module AWS + class SimpleDB + class Real + # Put items attributes into a SimpleDB domain + # + # ==== Parameters + # * domain_name<~String> - Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # * items<~Hash> - Keys are the items names and may use any UTF-8 + # characters valid in xml. Control characters and sequences not allowed + # in xml are not valid. Can be up to 1024 bytes long. Values are the + # attributes to add to the given item and may use any UTF-8 characters + # valid in xml. Control characters and sequences not allowed in xml are + # not valid. Each name and value can be up to 1024 bytes long. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage' + # * 'RequestId' + def batch_put_attributes(domain_name, items, replace_attributes = Hash.new([])) + request({ + 'Action' => 'BatchPutAttributes', + 'DomainName' => domain_name, + :parser => Fog::Parsers::AWS::SimpleDB::Basic.new(@nil_string) + }.merge!(encode_batch_attributes(items, replace_attributes))) + end + end + + class Mock + def batch_put_attributes(domain_name, items, replace_attributes = Hash.new([])) + response = Excon::Response.new + if self.data[:domains][domain_name] + for item_name, attributes in items do + for key, value in attributes do + self.data[:domains][domain_name][item_name] ||= {} + if replace_attributes[item_name] && replace_attributes[item_name].include?(key) + self.data[:domains][domain_name][item_name][key.to_s] = [] + else + self.data[:domains][domain_name][item_name][key.to_s] ||= [] + end + self.data[:domains][domain_name][item_name][key.to_s] << value.to_s + end + end + response.status = 200 + response.body = { + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'RequestId' => Fog::AWS::Mock.request_id + } + else + response.status = 400 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/create_domain.rb b/lib/fog/aws/requests/simpledb/create_domain.rb new file mode 100644 index 000000000..e192db131 --- /dev/null +++ b/lib/fog/aws/requests/simpledb/create_domain.rb @@ -0,0 +1,40 @@ +module Fog + module AWS + class SimpleDB + class Real + # Create a SimpleDB domain + # + # ==== Parameters + # * domain_name<~String>:: Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage' + # * 'RequestId' + def create_domain(domain_name) + request( + 'Action' => 'CreateDomain', + 'DomainName' => domain_name, + :idempotent => true, + :parser => Fog::Parsers::AWS::SimpleDB::Basic.new(@nil_string) + ) + end + end + + class Mock + def create_domain(domain_name) + response = Excon::Response.new + self.data[:domains][domain_name] = {} + response.status = 200 + response.body = { + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'RequestId' => Fog::AWS::Mock.request_id + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/delete_attributes.rb b/lib/fog/aws/requests/simpledb/delete_attributes.rb new file mode 100644 index 000000000..e1ccce9d5 --- /dev/null +++ b/lib/fog/aws/requests/simpledb/delete_attributes.rb @@ -0,0 +1,69 @@ +module Fog + module AWS + class SimpleDB + class Real + # List metadata for SimpleDB domain + # + # ==== Parameters + # * domain_name<~String> - Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # * item_name<~String> - Name of the item. May use any UTF-8 characters valid + # in xml. Control characters and sequences not allowed in xml are not + # valid. Can be up to 1024 bytes long. + # * attributes<~Hash> - Name/value pairs to remove from the item. Defaults to + # nil, which will delete the entire item. Attribute names and values may + # use any UTF-8 characters valid in xml. Control characters and sequences + # not allowed in xml are not valid. Each name and value can be up to 1024 + # bytes long. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage' + # * 'RequestId' + def delete_attributes(domain_name, item_name, attributes = nil) + request({ + 'Action' => 'DeleteAttributes', + 'DomainName' => domain_name, + 'ItemName' => item_name, + :parser => Fog::Parsers::AWS::SimpleDB::Basic.new(@nil_string) + }.merge!(encode_attributes(attributes))) + end + end + + class Mock + def delete_attributes(domain_name, item_name, attributes = nil) + response = Excon::Response.new + if self.data[:domains][domain_name] + if self.data[:domains][domain_name][item_name] + if attributes + for key, value in attributes + if self.data[:domains][domain_name][item_name][key] + if value.nil? || value.empty? + self.data[:domains][domain_name][item_name].delete(key) + else + for v in value + self.data[:domains][domain_name][item_name][key].delete(v) + end + end + end + end + else + self.data[:domains][domain_name][item_name].clear + end + end + response.status = 200 + response.body = { + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'RequestId' => Fog::AWS::Mock.request_id + } + else + response.status = 400 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/delete_domain.rb b/lib/fog/aws/requests/simpledb/delete_domain.rb new file mode 100644 index 000000000..217e3b9ca --- /dev/null +++ b/lib/fog/aws/requests/simpledb/delete_domain.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class SimpleDB + class Real + # Delete a SimpleDB domain + # + # ==== Parameters + # * domain_name<~String>:: Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage' + # * 'RequestId' + def delete_domain(domain_name) + request( + 'Action' => 'DeleteDomain', + 'DomainName' => domain_name, + :idempotent => true, + :parser => Fog::Parsers::AWS::SimpleDB::Basic.new(@nil_string) + ) + end + end + + class Mock + def delete_domain(domain_name) + response = Excon::Response.new + if self.data[:domains].delete(domain_name) + response.status = 200 + response.body = { + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'RequestId' => Fog::AWS::Mock.request_id + } + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/domain_metadata.rb b/lib/fog/aws/requests/simpledb/domain_metadata.rb new file mode 100644 index 000000000..2e04a7805 --- /dev/null +++ b/lib/fog/aws/requests/simpledb/domain_metadata.rb @@ -0,0 +1,72 @@ +module Fog + module AWS + class SimpleDB + class Real + require 'fog/aws/parsers/simpledb/domain_metadata' + + # List metadata for SimpleDB domain + # + # ==== Parameters + # * domain_name<~String> - Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'AttributeNameCount' - number of unique attribute names in domain + # * 'AttributeNamesSizeBytes' - total size of unique attribute names, in bytes + # * 'AttributeValueCount' - number of all name/value pairs in domain + # * 'AttributeValuesSizeBytes' - total size of attributes, in bytes + # * 'BoxUsage' + # * 'ItemCount' - number of items in domain + # * 'ItemNameSizeBytes' - total size of item names in domain, in bytes + # * 'RequestId' + # * 'Timestamp' - last update time for metadata. + def domain_metadata(domain_name) + request( + 'Action' => 'DomainMetadata', + 'DomainName' => domain_name, + :idempotent => true, + :parser => Fog::Parsers::AWS::SimpleDB::DomainMetadata.new(@nil_string) + ) + end + end + + class Mock + def domain_metadata(domain_name) + response = Excon::Response.new + if domain = self.data[:domains][domain_name] + response.status = 200 + + attribute_names = [] + attribute_values = [] + for item in domain.values + for key, values in item + attribute_names << key + for value in values + attribute_values << value + end + end + end + + response.body = { + 'AttributeNameCount' => attribute_names.length, + 'AttributeNamesSizeBytes' => attribute_names.join('').length, + 'AttributeValueCount' => attribute_values.length, + 'AttributeValuesSizeBytes' => attribute_values.join('').length, + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'ItemCount' => domain.keys.length, + 'ItemNamesSizeBytes' => domain.keys.join('').length, + 'RequestId' => Fog::AWS::Mock.request_id, + 'Timestamp' => Time.now + } + else + response.status = 400 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/get_attributes.rb b/lib/fog/aws/requests/simpledb/get_attributes.rb new file mode 100644 index 000000000..e0a911363 --- /dev/null +++ b/lib/fog/aws/requests/simpledb/get_attributes.rb @@ -0,0 +1,80 @@ +module Fog + module AWS + class SimpleDB + class Real + require 'fog/aws/parsers/simpledb/get_attributes' + + # List metadata for SimpleDB domain + # + # ==== Parameters + # * domain_name<~String> - Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # * item_name<~String> - Name of the item. May use any UTF-8 characters valid + # in xml. Control characters and sequences not allowed in xml are not + # valid. Can be up to 1024 bytes long. + # * options<~Hash>: + # * AttributeName<~Array> - Attributes to return from the item. Defaults to + # {}, which will return all attributes. Attribute names and values may use + # any UTF-8 characters valid in xml. Control characters and sequences not + # allowed in xml are not valid. Each name and value can be up to 1024 + # bytes long. + # * ConsistentRead<~Boolean> - When set to true, ensures most recent data is returned. Defaults to false. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Attributes' - list of attribute name/values for the item + # * 'BoxUsage' + # * 'RequestId' + def get_attributes(domain_name, item_name, options = {}) + if options.is_a?(Array) + Fog::Logger.deprecation("get_attributes with array attributes param is deprecated, use 'AttributeName' => attributes) instead [light_black](#{caller.first})[/]") + options = {'AttributeName' => options} + end + options['AttributeName'] ||= [] + request({ + 'Action' => 'GetAttributes', + 'ConsistentRead' => !!options['ConsistentRead'], + 'DomainName' => domain_name, + 'ItemName' => item_name, + :idempotent => true, + :parser => Fog::Parsers::AWS::SimpleDB::GetAttributes.new(@nil_string) + }.merge!(encode_attribute_names(options['AttributeName']))) + end + end + + class Mock + def get_attributes(domain_name, item_name, options = {}) + if options.is_a?(Array) + Fog::Logger.deprecation("get_attributes with array attributes param is deprecated, use 'AttributeName' => attributes) instead [light_black](#{caller.first})[/]") + options['AttributeName'] ||= options if options.is_a?(Array) + end + options['AttributeName'] ||= [] + response = Excon::Response.new + if self.data[:domains][domain_name] + object = {} + if !options['AttributeName'].empty? + for attribute in options['AttributeName'] + if self.data[:domains][domain_name].key?(item_name) && self.data[:domains][domain_name][item_name].key?(attribute) + object[attribute] = self.data[:domains][domain_name][item_name][attribute] + end + end + elsif self.data[:domains][domain_name][item_name] + object = self.data[:domains][domain_name][item_name] + end + response.status = 200 + response.body = { + 'Attributes' => object, + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'RequestId' => Fog::AWS::Mock.request_id + } + else + response.status = 400 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/list_domains.rb b/lib/fog/aws/requests/simpledb/list_domains.rb new file mode 100644 index 000000000..ef62b8ab9 --- /dev/null +++ b/lib/fog/aws/requests/simpledb/list_domains.rb @@ -0,0 +1,55 @@ +module Fog + module AWS + class SimpleDB + class Real + require 'fog/aws/parsers/simpledb/list_domains' + + # List SimpleDB domains + # + # ==== Parameters + # * options<~Hash> - options, defaults to {} + # * 'MaxNumberOfDomains'<~Integer> - number of domains to return + # between 1 and 100, defaults to 100 + # * 'NextToken'<~String> - Offset token to start listing, defaults to nil + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage' + # * 'Domains' - array of domain names. + # * 'NextToken' - offset to start with if there are are more domains to list + # * 'RequestId' + def list_domains(options = {}) + request({ + 'Action' => 'ListDomains', + :idempotent => true, + :parser => Fog::Parsers::AWS::SimpleDB::ListDomains.new(@nil_string) + }.merge!(options)) + end + end + + class Mock + def list_domains(options = {}) + response = Excon::Response.new + keys = self.data[:domains].keys + max = options['MaxNumberOfDomains'] || keys.size + offset = options['NextToken'] || 0 + domains = [] + for key, value in self.data[:domains].keys[offset...max] + domains << key + end + response.status = 200 + response.body = { + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'Domains' => domains, + 'RequestId' => Fog::AWS::Mock.request_id + } + if max < keys.size + response.body['NextToken'] = max + 1 + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/put_attributes.rb b/lib/fog/aws/requests/simpledb/put_attributes.rb new file mode 100644 index 000000000..bb40f7479 --- /dev/null +++ b/lib/fog/aws/requests/simpledb/put_attributes.rb @@ -0,0 +1,74 @@ +module Fog + module AWS + class SimpleDB + class Real + # Put item attributes into a SimpleDB domain + # + # ==== Parameters + # * domain_name<~String> - Name of domain. Must be between 3 and 255 of the + # following characters: a-z, A-Z, 0-9, '_', '-' and '.'. + # * item_name<~String> - Name of the item. May use any UTF-8 characters valid + # in xml. Control characters and sequences not allowed in xml are not + # valid. Can be up to 1024 bytes long. + # * attributes<~Hash> - Name/value pairs to add to the item. Attribute names + # and values may use any UTF-8 characters valid in xml. Control characters + # and sequences not allowed in xml are not valid. Each name and value can + # be up to 1024 bytes long. + # * options<~Hash> - Accepts the following keys. + # :replace => [Array of keys to replace] + # :expect => {name/value pairs for performing conditional put} + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage' + # * 'RequestId' + def put_attributes(domain_name, item_name, attributes, options = {}) + options[:expect] = {} unless options[:expect] + options[:replace] = [] unless options[:replace] + request({ + 'Action' => 'PutAttributes', + 'DomainName' => domain_name, + 'ItemName' => item_name, + :parser => Fog::Parsers::AWS::SimpleDB::Basic.new(@nil_string) + }.merge!(encode_attributes(attributes, options[:replace], options[:expect]))) + end + end + + class Mock + def put_attributes(domain_name, item_name, attributes, options = {}) + options[:expect] = {} unless options[:expect] + options[:replace] = [] unless options[:replace] + response = Excon::Response.new + if self.data[:domains][domain_name] + options[:expect].each do |ck, cv| + if self.data[:domains][domain_name][item_name][ck] != [cv] + response.status = 409 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + attributes.each do |key, value| + self.data[:domains][domain_name][item_name] ||= {} + self.data[:domains][domain_name][item_name][key.to_s] = [] unless self.data[:domains][domain_name][item_name][key.to_s] + if options[:replace].include?(key.to_s) + self.data[:domains][domain_name][item_name][key.to_s] = [*value].map {|x| x.to_s} + else + self.data[:domains][domain_name][item_name][key.to_s] += [*value].map {|x| x.to_s} + end + end + response.status = 200 + response.body = { + 'BoxUsage' => Fog::AWS::Mock.box_usage, + 'RequestId' => Fog::AWS::Mock.request_id + } + else + response.status = 400 + raise(Excon::Errors.status_error({:expects => 200}, response)) + + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/simpledb/select.rb b/lib/fog/aws/requests/simpledb/select.rb new file mode 100644 index 000000000..56d05c5ff --- /dev/null +++ b/lib/fog/aws/requests/simpledb/select.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class SimpleDB + class Real + require 'fog/aws/parsers/simpledb/select' + + # Select item data from SimpleDB + # + # ==== Parameters + # * select_expression<~String> - Expression to query domain with. + # * options<~Hash>: + # * ConsistentRead<~Boolean> - When set to true, ensures most recent data is returned. Defaults to false. + # * NextToken<~String> - Offset token to start list, defaults to nil. + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'BoxUsage'<~Float> + # * 'RequestId'<~String> + # * 'Items'<~Hash> - list of attribute name/values for the items formatted as + # { 'item_name' => { 'attribute_name' => ['attribute_value'] }} + # * 'NextToken'<~String> - offset to start with if there are are more domains to list + def select(select_expression, options = {}) + if options.is_a?(String) + Fog::Logger.deprecation("get_attributes with string next_token param is deprecated, use 'AttributeName' => attributes) instead [light_black](#{caller.first})[/]") + options = {'NextToken' => options} + end + options['NextToken'] ||= nil + request( + 'Action' => 'Select', + 'ConsistentRead' => !!options['ConsistentRead'], + 'NextToken' => options['NextToken'], + 'SelectExpression' => select_expression, + :idempotent => true, + :parser => Fog::Parsers::AWS::SimpleDB::Select.new(@nil_string) + ) + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/add_permission.rb b/lib/fog/aws/requests/sns/add_permission.rb new file mode 100644 index 000000000..6b6898697 --- /dev/null +++ b/lib/fog/aws/requests/sns/add_permission.rb @@ -0,0 +1,22 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/add_permission' + + def add_permission(options = {}) + request({ + 'Action' => 'AddPermission', + :parser => Fog::Parsers::AWS::SNS::AddPermission.new + }.merge!(options)) + end + end + + class Mock + def add_permission(options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/confirm_subscription.rb b/lib/fog/aws/requests/sns/confirm_subscription.rb new file mode 100644 index 000000000..75ecefb33 --- /dev/null +++ b/lib/fog/aws/requests/sns/confirm_subscription.rb @@ -0,0 +1,30 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/confirm_subscription' + + # Confirm a subscription + # + # ==== Parameters + # * arn<~String> - Arn of topic to confirm subscription to + # * token<~String> - Token sent to endpoint during subscribe action + # * options<~Hash>: + # * AuthenticateOnUnsubscribe<~Boolean> - whether or not unsubscription should be authenticated, defaults to false + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_ConfirmSubscription.html + # + + def confirm_subscription(arn, token, options = {}) + request({ + 'Action' => 'ConfirmSubscription', + 'Token' => token, + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::ConfirmSubscription.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/create_topic.rb b/lib/fog/aws/requests/sns/create_topic.rb new file mode 100644 index 000000000..bfb2a42b0 --- /dev/null +++ b/lib/fog/aws/requests/sns/create_topic.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/create_topic' + + # Create a topic + # + # ==== Parameters + # * name<~String> - Name of topic to create + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_CreateTopic.html + # + + def create_topic(name) + request({ + 'Action' => 'CreateTopic', + 'Name' => name, + :parser => Fog::Parsers::AWS::SNS::CreateTopic.new + }) + end + end + + class Mock + def create_topic(name) + response = Excon::Response.new + + topic_arn = Fog::AWS::Mock.arn(@module, @account_id, name, @region) + + self.data[:topics][topic_arn] = { + "Owner" => Fog::AWS::Mock.owner_id, + "SubscriptionsPending" => 0, + "SubscriptionsConfirmed" => 0, + "SubscriptionsDeleted" => 0, + "DisplayName" => name, + "TopicArn" => topic_arn, + "EffectiveDeliveryPolicy" => %Q|{"http":{"defaultHealthyRetryPolicy":{"minDelayTarget":20,"maxDelayTarget":20,"numRetries":3,"numMaxDelayRetries":0,"numNoDelayRetries":0,"numMinDelayRetries":0,"backoffFunction":"linear"},"disableSubscriptionOverrides":false}}|, + "Policy" => %Q|{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"Aws":"*"},"Action":["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"],"Resource":"arn:aws:sns:us-east-1:990279267269:Smithy","Condition":{"StringEquals":{"Aws:SourceOwner":"990279267269"}}}]}| + } + response.body = {"TopicArn" => topic_arn, "RequestId" => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/delete_topic.rb b/lib/fog/aws/requests/sns/delete_topic.rb new file mode 100644 index 000000000..2a094a776 --- /dev/null +++ b/lib/fog/aws/requests/sns/delete_topic.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/delete_topic' + + # Delete a topic + # + # ==== Parameters + # * arn<~String> - The Arn of the topic to delete + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_DeleteTopic.html + # + + def delete_topic(arn) + request({ + 'Action' => 'DeleteTopic', + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::DeleteTopic.new + }) + end + end + + class Mock + def delete_topic(arn) + self.data[:topics].delete(arn) + + response = Excon::Response.new + response.body = {"RequestId" => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/get_topic_attributes.rb b/lib/fog/aws/requests/sns/get_topic_attributes.rb new file mode 100644 index 000000000..083694402 --- /dev/null +++ b/lib/fog/aws/requests/sns/get_topic_attributes.rb @@ -0,0 +1,36 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/get_topic_attributes' + + # Get attributes of a topic + # + # ==== Parameters + # * arn<~Hash>: The Arn of the topic to get attributes for + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_GetTopicAttributes.html + # + + def get_topic_attributes(arn) + request({ + 'Action' => 'GetTopicAttributes', + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::GetTopicAttributes.new + }) + end + end + + class Mock + def get_topic_attributes(arn) + response = Excon::Response.new + attributes = self.data[:topics][arn] + + response.body = {"Attributes" => attributes, "RequestId" => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/list_subscriptions.rb b/lib/fog/aws/requests/sns/list_subscriptions.rb new file mode 100644 index 000000000..fd1585ecf --- /dev/null +++ b/lib/fog/aws/requests/sns/list_subscriptions.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/list_subscriptions' + + # List subscriptions + # + # ==== Parameters + # * options<~Hash>: + # * 'NextToken'<~String> - Token returned from previous request, used for pagination + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_ListSubscriptions.html + # + + def list_subscriptions(options = {}) + request({ + 'Action' => 'ListSubscriptions', + :parser => Fog::Parsers::AWS::SNS::ListSubscriptions.new + }.merge!(options)) + end + end + + class Mock + def list_subscriptions(options={}) + response = Excon::Response.new + + response.body = {'Subscriptions' => self.data[:subscriptions].values, 'RequestId' => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/list_subscriptions_by_topic.rb b/lib/fog/aws/requests/sns/list_subscriptions_by_topic.rb new file mode 100644 index 000000000..5b7214bdc --- /dev/null +++ b/lib/fog/aws/requests/sns/list_subscriptions_by_topic.rb @@ -0,0 +1,39 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/list_subscriptions' + + # List subscriptions for a topic + # + # ==== Parameters + # * arn<~String> - Arn of topic to list subscriptions for + # * options<~Hash>: + # * 'NextToken'<~String> - Token returned from previous request, used for pagination + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_ListSubscriptionsByTopic.html + # + + def list_subscriptions_by_topic(arn, options = {}) + request({ + 'Action' => 'ListSubscriptionsByTopic', + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::ListSubscriptions.new + }.merge!(options)) + end + end + + class Mock + def list_subscriptions_by_topic(arn, options={}) + response = Excon::Response.new + + subscriptions = self.data[:subscriptions].values.select { |s| s["TopicArn"] == arn } + + response.body = {'Subscriptions' => subscriptions, 'RequestId' => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/list_topics.rb b/lib/fog/aws/requests/sns/list_topics.rb new file mode 100644 index 000000000..e6d1dd84c --- /dev/null +++ b/lib/fog/aws/requests/sns/list_topics.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/list_topics' + + # List topics + # + # ==== Parameters + # * options<~Hash>: + # * 'NextToken'<~String> - Token returned from previous request, used for pagination + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_ListTopics.html + # + + def list_topics(options = {}) + request({ + 'Action' => 'ListTopics', + :parser => Fog::Parsers::AWS::SNS::ListTopics.new + }.merge!(options)) + end + end + + class Mock + def list_topics(options={}) + response = Excon::Response.new + + response.body = {'Topics' => self.data[:topics].keys, 'RequestId' => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/publish.rb b/lib/fog/aws/requests/sns/publish.rb new file mode 100644 index 000000000..d161fedba --- /dev/null +++ b/lib/fog/aws/requests/sns/publish.rb @@ -0,0 +1,31 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/publish' + + # Send a message to a topic + # + # ==== Parameters + # * arn<~String> - Arn of topic to send message to + # * message<~String> - Message to send to topic + # * options<~Hash>: + # * MessageStructure<~String> - message structure, in ['json'] + # * Subject<~String> - value to use for subject when delivering by email + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_Publish.html + # + + def publish(arn, message, options = {}) + request({ + 'Action' => 'Publish', + 'Message' => message, + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::Publish.new + }.merge!(options)) + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/remove_permission.rb b/lib/fog/aws/requests/sns/remove_permission.rb new file mode 100644 index 000000000..743b00beb --- /dev/null +++ b/lib/fog/aws/requests/sns/remove_permission.rb @@ -0,0 +1,22 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/remove_permission' + + def remove_permission(options = {}) + request({ + 'Action' => 'RemovePermission', + :parser => Fog::Parsers::AWS::SNS::RemovePermission.new + }.merge!(options)) + end + end + + class Mock + def remove_permission(options = {}) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/set_topic_attributes.rb b/lib/fog/aws/requests/sns/set_topic_attributes.rb new file mode 100644 index 000000000..088300761 --- /dev/null +++ b/lib/fog/aws/requests/sns/set_topic_attributes.rb @@ -0,0 +1,45 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/set_topic_attributes' + + # Set attributes of a topic + # + # ==== Parameters + # * arn<~Hash> - The Arn of the topic to get attributes for + # * attribute_name<~String> - Name of attribute to set, in ['DisplayName', 'Policy'] + # * attribute_value<~String> - Value to set attribute to + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_SetTopicAttributes.html + # + + def set_topic_attributes(arn, attribute_name, attribute_value) + request({ + 'Action' => 'SetTopicAttributes', + 'AttributeName' => attribute_name, + 'AttributeValue' => attribute_value, + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::SetTopicAttributes.new + }) + end + end + + class Mock + def set_topic_attributes(arn, attribute_name, attribute_value) + attributes = self.data[:topics][arn] + + if %w(Policy DisplayName DeliveryPolicy).include?(attribute_name) + attributes[attribute_name] = attribute_value + self.data[:topics][arn] = attributes + end + + response = Excon::Response.new + response.body = {"RequestId" => Fog::AWS::Mock.request_id} + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/subscribe.rb b/lib/fog/aws/requests/sns/subscribe.rb new file mode 100644 index 000000000..49605db44 --- /dev/null +++ b/lib/fog/aws/requests/sns/subscribe.rb @@ -0,0 +1,85 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/subscribe' + + # Create a subscription + # + # ==== Parameters + # * arn<~String> - Arn of topic to subscribe to + # * endpoint<~String> - Endpoint to notify + # * protocol<~String> - Protocol to notify endpoint with, in ['email', 'email-json', 'http', 'https', 'sqs'] + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_Subscribe.html + # + + def subscribe(arn, endpoint, protocol) + request({ + 'Action' => 'Subscribe', + 'Endpoint' => endpoint, + 'Protocol' => protocol, + 'TopicArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::Subscribe.new + }) + end + end + + class Mock + def subscribe(arn, endpoint, protocol) + response = Excon::Response.new + + unless topic = self.data[:topics][arn] + response.status = 400 + response.body = { + 'Code' => 'InvalidParameterValue', + 'Message' => 'Invalid parameter: TopicArn', + 'Type' => 'Sender', + } + + return response + end + + subscription_arn = Fog::AWS::Mock.arn(@module, @account_id, "#{topic["DisplayName"]}:#{Fog::AWS::Mock.request_id}", @region) + + self.data[:subscriptions][subscription_arn] = { + "Protocol" => protocol, + "Owner" => @account_id.to_s, + "TopicArn" => arn, + "SubscriptionArn" => subscription_arn, + "Endpoint" => endpoint, + } + + access_key, _ = Fog::AWS::SQS.data.values.find { |_, data| !!data[:queues][endpoint] } + + if protocol == "sqs" && access_key + token = SecureRandom.hex(128) + message = "You have chosen to subscribe to the topic #{arn}.\nTo confirm the subscription, visit the SubscribeURL included in this message." + signature = Fog::HMAC.new("sha256", token).sign(message) + + Fog::AWS::SQS.new( + :region => self.region, + :aws_access_key_id => access_key, + :aws_secret_access_key => @aws_secret_access_key, + ).send_message(endpoint, { + "Type" => "SubscriptionConfirmation", + "MessageId" => SecureRandom.uuid, + "Token" => token, + "TopicArn" => arn, + "Message" => message, + "SubscribeURL" => "https://sns.#{self.region}.amazonaws.com/?Action=ConfirmSubscription&TopicArn=#{arn}&Token=#{token}", + "Timestamp" => Time.now.iso8601, + "SignatureVersion" => "1", + "Signature" => signature, + "SigningCertURL" => "https://sns.#{self.region}.amazonaws.com/SimpleNotificationService-#{SecureRandom.hex(16)}.pem" + }) + end + + response.body = { 'SubscriptionArn' => 'pending confirmation', 'RequestId' => Fog::AWS::Mock.request_id } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/sns/unsubscribe.rb b/lib/fog/aws/requests/sns/unsubscribe.rb new file mode 100644 index 000000000..dbeb4f8a0 --- /dev/null +++ b/lib/fog/aws/requests/sns/unsubscribe.rb @@ -0,0 +1,26 @@ +module Fog + module AWS + class SNS + class Real + require 'fog/aws/parsers/sns/unsubscribe' + + # Delete a subscription + # + # ==== Parameters + # * arn<~String> - Arn of subscription to delete + # + # ==== See Also + # http://docs.amazonwebservices.com/sns/latest/api/API_Unsubscribe.html + # + + def unsubscribe(arn) + request({ + 'Action' => 'Unsubscribe', + 'SubscriptionArn' => arn.strip, + :parser => Fog::Parsers::AWS::SNS::Unsubscribe.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/change_message_visibility.rb b/lib/fog/aws/requests/sqs/change_message_visibility.rb new file mode 100644 index 000000000..017f033c8 --- /dev/null +++ b/lib/fog/aws/requests/sqs/change_message_visibility.rb @@ -0,0 +1,58 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/basic' + + # Change visibility timeout for a message + # + # ==== Parameters + # * queue_url<~String> - Url of queue for message to update + # * receipt_handle<~String> - Token from previous recieve message + # * visibility_timeout<~Integer> - New visibility timeout in 0..43200 + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryChangeMessageVisibility.html + # + + def change_message_visibility(queue_url, receipt_handle, visibility_timeout) + request({ + 'Action' => 'ChangeMessageVisibility', + 'ReceiptHandle' => receipt_handle, + 'VisibilityTimeout' => visibility_timeout, + :parser => Fog::Parsers::AWS::SQS::Basic.new, + :path => path_from_queue_url(queue_url) + }) + end + end + + class Mock + def change_message_visibility(queue_url, receipt_handle, visibility_timeout) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + message_id, _ = queue[:receipt_handles].find { |message_id, receipts| + receipts.key?(receipt_handle) + } + + if message_id + queue[:messages][message_id]['Attributes']['VisibilityTimeout'] = visibility_timeout + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + response.status = 200 + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/create_queue.rb b/lib/fog/aws/requests/sqs/create_queue.rb new file mode 100644 index 000000000..f7da618d0 --- /dev/null +++ b/lib/fog/aws/requests/sqs/create_queue.rb @@ -0,0 +1,62 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/create_queue' + + # Create a queue + # + # ==== Parameters + # * name<~String> - Name of queue to create + # * options<~Hash>: + # * DefaultVisibilityTimeout<~String> - Time, in seconds, to hide a message after it has been received, in 0..43200, defaults to 30 + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryCreateQueue.html + # + + def create_queue(name, options = {}) + request({ + 'Action' => 'CreateQueue', + 'QueueName' => name, + :parser => Fog::Parsers::AWS::SQS::CreateQueue.new + }.merge!(options)) + end + end + + class Mock + def create_queue(name, options = {}) + Excon::Response.new.tap do |response| + response.status = 200 + + now = Time.now + queue_url = "https://queue.amazonaws.com/#{data[:owner_id]}/#{name}" + queue = { + 'QueueName' => name, + 'Attributes' => { + 'VisibilityTimeout' => 30, + 'ApproximateNumberOfMessages' => 0, + 'ApproximateNumberOfMessagesNotVisible' => 0, + 'CreatedTimestamp' => now, + 'LastModifiedTimestamp' => now, + 'QueueArn' => Fog::AWS::Mock.arn('sqs', 'us-east-1', data[:owner_id], name), + 'MaximumMessageSize' => 8192, + 'MessageRetentionPeriod' => 345600 + }, + :messages => {}, + :receipt_handles => {} + } + data[:queues][queue_url] = queue unless data[:queues][queue_url] + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'QueueUrl' => queue_url + } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/delete_message.rb b/lib/fog/aws/requests/sqs/delete_message.rb new file mode 100644 index 000000000..8948990d1 --- /dev/null +++ b/lib/fog/aws/requests/sqs/delete_message.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/basic' + + # Delete a message from a queue + # + # ==== Parameters + # * queue_url<~String> - Url of queue to delete message from + # * receipt_handle<~String> - Token from previous recieve message + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryDeleteMessage.html + # + + def delete_message(queue_url, receipt_handle) + request({ + 'Action' => 'DeleteMessage', + 'ReceiptHandle' => receipt_handle, + :parser => Fog::Parsers::AWS::SQS::Basic.new, + :path => path_from_queue_url(queue_url), + }) + end + end + + class Mock + def delete_message(queue_url, receipt_handle) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + message_id, _ = queue[:receipt_handles].find { |msg_id, receipts| + receipts.key?(receipt_handle) + } + + if message_id + queue[:receipt_handles].delete(message_id) + queue[:messages].delete(message_id) + queue['Attributes']['LastModifiedTimestamp'] = Time.now + end + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + response.status = 200 + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/delete_queue.rb b/lib/fog/aws/requests/sqs/delete_queue.rb new file mode 100644 index 000000000..c521bae92 --- /dev/null +++ b/lib/fog/aws/requests/sqs/delete_queue.rb @@ -0,0 +1,47 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/basic' + + # Delete a queue + # + # ==== Parameters + # * queue_url<~String> - Url of queue to delete + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryDeleteQueue.html + # + + def delete_queue(queue_url) + request({ + 'Action' => 'DeleteQueue', + :parser => Fog::Parsers::AWS::SQS::Basic.new, + :path => path_from_queue_url(queue_url), + }) + end + end + + class Mock + def delete_queue(queue_url) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + response.status = 200 + + data[:queues].delete(queue_url) + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/get_queue_attributes.rb b/lib/fog/aws/requests/sqs/get_queue_attributes.rb new file mode 100644 index 000000000..511903d8a --- /dev/null +++ b/lib/fog/aws/requests/sqs/get_queue_attributes.rb @@ -0,0 +1,48 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/get_queue_attributes' + + # Get attributes of a queue + # + # ==== Parameters + # * queue_url<~String> - Url of queue to get attributes for + # * attribute_name<~Array> - Name of attribute to return, in ['All', 'ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesNotVisible', 'CreatedTimestamp', 'LastModifiedTimestamp', 'MaximumMessageSize', 'MessageRetentionPeriod', 'Policy', 'QueueArn', 'VisibilityTimeout'] + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryGetQueueAttributes.html + # + + def get_queue_attributes(queue_url, attribute_name) + request({ + 'Action' => 'GetQueueAttributes', + 'AttributeName' => attribute_name, + :path => path_from_queue_url(queue_url), + :parser => Fog::Parsers::AWS::SQS::GetQueueAttributes.new + }) + end + end + + class Mock + def get_queue_attributes(queue_url, attribute_name) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'Attributes' => queue['Attributes'] + } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/list_queues.rb b/lib/fog/aws/requests/sqs/list_queues.rb new file mode 100644 index 000000000..cf3a920ba --- /dev/null +++ b/lib/fog/aws/requests/sqs/list_queues.rb @@ -0,0 +1,41 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/list_queues' + + # List queues + # + # ==== Parameters + # * options<~Hash>: + # * QueueNamePrefix<~String> - String used to filter results to only those with matching prefixes + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryListQueues.html + # + + def list_queues(options = {}) + request({ + 'Action' => 'ListQueues', + :parser => Fog::Parsers::AWS::SQS::ListQueues.new + }.merge!(options)) + end + end + + class Mock + def list_queues(options = {}) + Excon::Response.new.tap do |response| + response.status = 200 + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'QueueUrls' => data[:queues].keys + } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/receive_message.rb b/lib/fog/aws/requests/sqs/receive_message.rb new file mode 100644 index 000000000..81f995634 --- /dev/null +++ b/lib/fog/aws/requests/sqs/receive_message.rb @@ -0,0 +1,83 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/receive_message' + + # Get a message from a queue (marks it as unavailable temporarily, but does not remove from queue, see delete_message) + # + # ==== Parameters + # * queue_url<~String> - Url of queue to get message from + # * options<~Hash>: + # * Attributes<~Array> - List of attributes to return, in ['All', 'ApproximateFirstReceiveTimestamp', 'ApproximateReceiveCount', 'SenderId', 'SentTimestamp'], defaults to 'All' + # * MaxNumberOfMessages<~Integer> - Maximum number of messages to return, defaults to 1 + # * VisibilityTimeout<~Integer> - Duration, in seconds, to hide message from other receives. In 0..43200, defaults to visibility timeout for queue + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QueryReceiveMessage.html + # + + def receive_message(queue_url, options = {}) + request({ + 'Action' => 'ReceiveMessage', + 'AttributeName' => 'All', + :path => path_from_queue_url(queue_url), + :parser => Fog::Parsers::AWS::SQS::ReceiveMessage.new + }.merge!(options)) + end + end + + class Mock + def receive_message(queue_url, options = {}) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + max_number_of_messages = options['MaxNumberOfMessages'] || 1 + now = Time.now + + messages = [] + + queue[:messages].values.each do |m| + message_id = m['MessageId'] + + invisible = if (received_handles = queue[:receipt_handles][message_id]) + visibility_timeout = m['Attributes']['VisibilityTimeout'] || queue['Attributes']['VisibilityTimeout'] + received_handles.any? { |handle, time| now < time + visibility_timeout } + else + false + end + + unless invisible + receipt_handle = Fog::Mock.random_base64(300) + + queue[:receipt_handles][message_id] ||= {} + queue[:receipt_handles][message_id][receipt_handle] = now + + m['Attributes'].tap do |attrs| + attrs['ApproximateFirstReceiveTimestamp'] ||= now + attrs['ApproximateReceiveCount'] = (attrs['ApproximateReceiveCount'] || 0) + 1 + end + + messages << m.merge({ + 'ReceiptHandle' => receipt_handle + }) + break if messages.size >= max_number_of_messages + end + end + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'Message' => messages + } + response.status = 200 + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/send_message.rb b/lib/fog/aws/requests/sqs/send_message.rb new file mode 100644 index 000000000..8126cc0d1 --- /dev/null +++ b/lib/fog/aws/requests/sqs/send_message.rb @@ -0,0 +1,65 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/send_message' + + # Add a message to a queue + # + # ==== Parameters + # * queue_url<~String> - Url of queue to add message to + # * message<~String> - Message to add to queue + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QuerySendMessage.html + # + + def send_message(queue_url, message) + request({ + 'Action' => 'SendMessage', + 'MessageBody' => message, + :path => path_from_queue_url(queue_url), + :parser => Fog::Parsers::AWS::SQS::SendMessage.new + }) + end + end + + class Mock + def send_message(queue_url, message) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + response.status = 200 + + now = Time.now + message_id = Fog::AWS::Mock.sqs_message_id + md5 = Digest::MD5.hexdigest(message) + + queue[:messages][message_id] = { + 'MessageId' => message_id, + 'Body' => message, + 'MD5OfBody' => md5, + 'Attributes' => { + 'SenderId' => Fog::AWS::Mock.sqs_message_id, + 'SentTimestamp' => now + } + } + + queue['Attributes']['LastModifiedTimestamp'] = now + + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + }, + 'MessageId' => message_id, + 'MD5OfMessageBody' => md5 + } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sqs/set_queue_attributes.rb b/lib/fog/aws/requests/sqs/set_queue_attributes.rb new file mode 100644 index 000000000..778d44fb0 --- /dev/null +++ b/lib/fog/aws/requests/sqs/set_queue_attributes.rb @@ -0,0 +1,49 @@ +module Fog + module AWS + class SQS + class Real + require 'fog/aws/parsers/sqs/basic' + + # Get attributes of a queue + # + # ==== Parameters + # * queue_url<~String> - Url of queue to get attributes for + # * attribute_name<~String> - Name of attribute to set, keys in ['MaximumMessageSize', 'MessageRetentionPeriod', 'Policy', 'VisibilityTimeout'] + # * attribute_value<~String> - Value to set for attribute + # + # ==== See Also + # http://docs.amazonwebservices.com/AwsSimpleQueueService/latest/APIReference/Query_QuerySetQueueAttributes.html + # + + def set_queue_attributes(queue_url, attribute_name, attribute_value) + request({ + 'Action' => 'SetQueueAttributes', + 'Attribute.Name' => attribute_name, + 'Attribute.Value' => attribute_value, + :path => path_from_queue_url(queue_url), + :parser => Fog::Parsers::AWS::SQS::Basic.new + }) + end + end + + class Mock + def set_queue_attributes(queue_url, attribute_name, attribute_value) + Excon::Response.new.tap do |response| + if (queue = data[:queues][queue_url]) + response.status = 200 + queue['Attributes'][attribute_name] = attribute_value + response.body = { + 'ResponseMetadata' => { + 'RequestId' => Fog::AWS::Mock.request_id + } + } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/abort_multipart_upload.rb b/lib/fog/aws/requests/storage/abort_multipart_upload.rb new file mode 100644 index 000000000..ecd35a477 --- /dev/null +++ b/lib/fog/aws/requests/storage/abort_multipart_upload.rb @@ -0,0 +1,45 @@ +module Fog + module Storage + class Aws + class Real + # + # Abort a multipart upload + # + # @param [String] bucket_name Name of bucket to abort multipart upload on + # @param [String] object_name Name of object to abort multipart upload on + # @param [String] upload_id Id of upload to add part to + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadAbort.html + # + def abort_multipart_upload(bucket_name, object_name, upload_id) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'DELETE', + :query => {'uploadId' => upload_id} + }) + end + end # Real + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/shared_mock_methods' + include Fog::Storage::AWS::SharedMockMethods + + def abort_multipart_upload(bucket_name, object_name, upload_id) + verify_mock_bucket_exists(bucket_name) + upload_info = get_upload_info(bucket_name, upload_id, true) + response = Excon::Response.new + if upload_info + response.status = 204 + response + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 204}, response)) + end + end + end # Mock + end # Storage + end # Aws +end # Fog diff --git a/lib/fog/aws/requests/storage/acl_utils.rb b/lib/fog/aws/requests/storage/acl_utils.rb new file mode 100644 index 000000000..ecf47e931 --- /dev/null +++ b/lib/fog/aws/requests/storage/acl_utils.rb @@ -0,0 +1,60 @@ +module Fog + module Storage + class Aws + require 'fog/aws/parsers/storage/access_control_list' + + private + def self.hash_to_acl(acl) + data = "\n" + + if acl['Owner'] && (acl['Owner']['ID'] || acl['Owner']['DisplayName']) + data << " \n" + data << " #{acl['Owner']['ID']}\n" if acl['Owner']['ID'] + data << " #{acl['Owner']['DisplayName']}\n" if acl['Owner']['DisplayName'] + data << " \n" + end + + grants = [acl['AccessControlList']].flatten.compact + + data << " \n" if grants.any? + grants.each do |grant| + data << " \n" + grantee = grant['Grantee'] + type = case + when grantee.key?('ID') + 'CanonicalUser' + when grantee.key?('EmailAddress') + 'AmazonCustomerByEmail' + when grantee.key?('URI') + 'Group' + end + + data << " \n" + case type + when 'CanonicalUser' + data << " #{grantee['ID']}\n" if grantee['ID'] + data << " #{grantee['DisplayName']}\n" if grantee['DisplayName'] + when 'AmazonCustomerByEmail' + data << " #{grantee['EmailAddress']}\n" if grantee['EmailAddress'] + when 'Group' + data << " #{grantee['URI']}\n" if grantee['URI'] + end + data << " \n" + data << " #{grant['Permission']}\n" + data << " \n" + end + data << " \n" if grants.any? + + data << "" + + data + end + + def self.acl_to_hash(acl_xml) + parser = Fog::Parsers::Storage::AWS::AccessControlList.new + Nokogiri::XML::SAX::Parser.new(parser).parse(acl_xml) + parser.response + end + end + end +end diff --git a/lib/fog/aws/requests/storage/complete_multipart_upload.rb b/lib/fog/aws/requests/storage/complete_multipart_upload.rb new file mode 100644 index 000000000..46094e16a --- /dev/null +++ b/lib/fog/aws/requests/storage/complete_multipart_upload.rb @@ -0,0 +1,73 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/complete_multipart_upload' + + # Complete a multipart upload + # + # @param [String] bucket_name Name of bucket to complete multipart upload for + # @param [String] object_name Name of object to complete multipart upload for + # @param [String] upload_id Id of upload to add part to + # @param [Array] parts Array of etags as Strings for parts + # + # @return [Excon::Response] + # * body [Hash]: (success) + # * Bucket [String] - bucket of new object + # * ETag [String] - etag of new object + # * Key [String] - key of new object + # * Location [String] - location of new object + # * body [Hash]: (failure) + # * Code [String] - Error status code + # * Message [String] - Error description + # + # @note This request could fail and still return +200 OK+, so it's important that you check the response. + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadComplete.html + # + def complete_multipart_upload(bucket_name, object_name, upload_id, parts) + data = "" + parts.each_with_index do |part, index| + data << "" + data << "#{index + 1}" + data << "#{part}" + data << "" + end + data << "" + request({ + :body => data, + :expects => 200, + :headers => { 'Content-Length' => data.length }, + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'POST', + :parser => Fog::Parsers::Storage::AWS::CompleteMultipartUpload.new, + :query => {'uploadId' => upload_id} + }) + end + end # Real + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/shared_mock_methods' + include Fog::Storage::AWS::SharedMockMethods + + def complete_multipart_upload(bucket_name, object_name, upload_id, parts) + bucket = verify_mock_bucket_exists(bucket_name) + upload_info = get_upload_info(bucket_name, upload_id, true) + body = parts.map { |pid| upload_info[:parts][pid.to_i] }.join + object = store_mock_object(bucket, object_name, body, upload_info[:options]) + + response = Excon::Response.new + response.status = 200 + response.body = { + 'Location' => "http://#{bucket_name}.s3.amazonaws.com/#{object_name}", + 'Bucket' => bucket_name, + 'Key' => object_name, + 'ETag' => object['ETag'], + } + response.headers['x-amz-version-id'] = object['VersionId'] if object['VersionId'] != 'null' + response + end + end # Mock + end # Storage + end # Aws +end # Fog diff --git a/lib/fog/aws/requests/storage/copy_object.rb b/lib/fog/aws/requests/storage/copy_object.rb new file mode 100644 index 000000000..ca5d13f7d --- /dev/null +++ b/lib/fog/aws/requests/storage/copy_object.rb @@ -0,0 +1,77 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/copy_object' + + # Copy an object from one S3 bucket to another + # + # @param source_bucket_name [String] Name of source bucket + # @param source_object_name [String] Name of source object + # @param target_bucket_name [String] Name of bucket to create copy in + # @param target_object_name [String] Name for new copy of object + # + # @param options [Hash]: + # @option options [String] x-amz-metadata-directive Specifies whether to copy metadata from source or replace with data in request. Must be in ['COPY', 'REPLACE'] + # @option options [String] x-amz-copy_source-if-match Copies object if its etag matches this value + # @option options [Time] x-amz-copy_source-if-modified_since Copies object it it has been modified since this time + # @option options [String] x-amz-copy_source-if-none-match Copies object if its etag does not match this value + # @option options [Time] x-amz-copy_source-if-unmodified-since Copies object it it has not been modified since this time + # @option options [String] x-amz-storage-class Default is 'STANDARD', set to 'REDUCED_REDUNDANCY' for non-critical, reproducable data + # + # + # @return [Excon::Response] + # * body [Hash]: + # * ETag [String] - etag of new object + # * LastModified [Time] - date object was last modified + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectCOPY.html + # + def copy_object(source_bucket_name, source_object_name, target_bucket_name, target_object_name, options = {}) + headers = { 'x-amz-copy-source' => "/#{source_bucket_name}#{object_to_path(source_object_name)}" }.merge!(options) + request({ + :expects => 200, + :headers => headers, + :bucket_name => target_bucket_name, + :object_name => target_object_name, + :method => 'PUT', + :parser => Fog::Parsers::Storage::AWS::CopyObject.new, + }) + end + end + + class Mock # :nodoc:all + def copy_object(source_bucket_name, source_object_name, target_bucket_name, target_object_name, options = {}) + response = Excon::Response.new + source_bucket = self.data[:buckets][source_bucket_name] + source_object = source_bucket && source_bucket[:objects][source_object_name] && source_bucket[:objects][source_object_name].first + target_bucket = self.data[:buckets][target_bucket_name] + + acl = options['x-amz-acl'] || 'private' + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + else + self.data[:acls][:object][target_bucket_name] ||= {} + self.data[:acls][:object][target_bucket_name][target_object_name] = self.class.acls(acl) + end + + if source_object && target_bucket + response.status = 200 + target_object = source_object.dup + target_object.merge!({'Key' => target_object_name}) + target_bucket[:objects][target_object_name] = [target_object] + response.body = { + 'ETag' => target_object['ETag'], + 'LastModified' => Time.parse(target_object['Last-Modified']) + } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/cors_utils.rb b/lib/fog/aws/requests/storage/cors_utils.rb new file mode 100644 index 000000000..6caafba12 --- /dev/null +++ b/lib/fog/aws/requests/storage/cors_utils.rb @@ -0,0 +1,39 @@ +module Fog + module Storage + class Aws + require 'fog/aws/parsers/storage/cors_configuration' + + private + + def self.hash_to_cors(cors) + data = "\n" + + [cors['CORSConfiguration']].flatten.compact.each do |rule| + data << " \n" + + ['ID', 'MaxAgeSeconds'].each do |key| + data << " <#{key}>#{rule[key]}\n" if rule[key] + end + + ['AllowedOrigin', 'AllowedMethod', 'AllowedHeader', 'ExposeHeader'].each do |key| + [rule[key]].flatten.compact.each do |value| + data << " <#{key}>#{value}\n" + end + end + + data << " \n" + end + + data << "" + + data + end + + def self.cors_to_hash(cors_xml) + parser = Fog::Parsers::Storage::AWS::CorsConfiguration.new + Nokogiri::XML::SAX::Parser.new(parser).parse(cors_xml) + parser.response + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket.rb b/lib/fog/aws/requests/storage/delete_bucket.rb new file mode 100644 index 000000000..4a5d1b9ec --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket.rb @@ -0,0 +1,42 @@ +module Fog + module Storage + class Aws + class Real + # Delete an S3 bucket + # + # @param bucket_name [String] name of bucket to delete + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETE.html + + def delete_bucket(bucket_name) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'DELETE' + }) + end + end + + class Mock # :nodoc:all + def delete_bucket(bucket_name) + response = Excon::Response.new + if self.data[:buckets][bucket_name].nil? + response.status = 404 + raise(Excon::Errors.status_error({:expects => 204}, response)) + elsif self.data[:buckets][bucket_name] && !self.data[:buckets][bucket_name][:objects].empty? + response.status = 409 + raise(Excon::Errors.status_error({:expects => 204}, response)) + else + self.data[:buckets].delete(bucket_name) + response.status = 204 + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket_cors.rb b/lib/fog/aws/requests/storage/delete_bucket_cors.rb new file mode 100644 index 000000000..a75e1e237 --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket_cors.rb @@ -0,0 +1,26 @@ +module Fog + module Storage + class Aws + class Real + # Deletes the cors configuration information set for the bucket. + # + # @param bucket_name [String] name of bucket to delete cors rules from + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEcors.html + + def delete_bucket_cors(bucket_name) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'DELETE', + :query => {'cors' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb b/lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb new file mode 100644 index 000000000..153254591 --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb @@ -0,0 +1,26 @@ +module Fog + module Storage + class Aws + class Real + # Delete lifecycle configuration for a bucket + # + # @param bucket_name [String] name of bucket to delete lifecycle configuration from + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETElifecycle.html + + def delete_bucket_lifecycle(bucket_name) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'DELETE', + :query => {'lifecycle' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket_policy.rb b/lib/fog/aws/requests/storage/delete_bucket_policy.rb new file mode 100644 index 000000000..7f2155011 --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket_policy.rb @@ -0,0 +1,26 @@ +module Fog + module Storage + class Aws + class Real + # Delete policy for a bucket + # + # @param bucket_name [String] name of bucket to delete policy from + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEpolicy.html + + def delete_bucket_policy(bucket_name) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'DELETE', + :query => {'policy' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket_tagging.rb b/lib/fog/aws/requests/storage/delete_bucket_tagging.rb new file mode 100644 index 000000000..07bf6c8be --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket_tagging.rb @@ -0,0 +1,41 @@ +module Fog + module Storage + class Aws + class Real + # Delete tagging for a bucket + # + # @param bucket_name [String] name of bucket to delete tagging from + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketDELETEtagging.html + + def delete_bucket_tagging(bucket_name) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'DELETE', + :query => {'tagging' => nil} + }) + end + end + + class Mock # :nodoc:all + def delete_bucket_tagging(bucket_name) + response = Excon::Response.new + if self.data[:buckets][bucket_name] + self.data[:bucket_tagging].delete(bucket_name) + response.status = 204 + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 204}, response)) + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket_website.rb b/lib/fog/aws/requests/storage/delete_bucket_website.rb new file mode 100644 index 000000000..6b6c998f9 --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket_website.rb @@ -0,0 +1,26 @@ +module Fog + module Storage + class Aws + class Real + # Delete website configuration for a bucket + # + # @param bucket_name [String] name of bucket to delete website configuration from + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEwebsite.html + + def delete_bucket_website(bucket_name) + request({ + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'DELETE', + :query => {'website' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_multiple_objects.rb b/lib/fog/aws/requests/storage/delete_multiple_objects.rb new file mode 100644 index 000000000..1363b8bfe --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_multiple_objects.rb @@ -0,0 +1,164 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/delete_multiple_objects' + + # Delete multiple objects from S3 + # @note For versioned deletes, options should include a version_ids hash, which + # maps from filename to an array of versions. + # The semantics are that for each (object_name, version) tuple, the + # caller must insert the object_name and an associated version (if + # desired), so for n versions, the object must be inserted n times. + # + # @param bucket_name [String] Name of bucket containing object to delete + # @param object_names [Array] Array of object names to delete + # + # @return [Excon::Response] response: + # * body [Hash]: + # * DeleteResult [Array]: + # * Deleted [Hash]: + # * Key [String] - Name of the object that was deleted + # * VersionId [String] - ID for the versioned onject in case of a versioned delete + # * DeleteMarker [Boolean] - Indicates if the request accessed a delete marker + # * DeleteMarkerVersionId [String] - Version ID of the delete marker accessed + # * Error [Hash]: + # * Key [String] - Name of the object that failed to be deleted + # * VersionId [String] - ID of the versioned object that was attempted to be deleted + # * Code [String] - Status code for the result of the failed delete + # * Message [String] - Error description + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/multiobjectdeleteapi.html + + def delete_multiple_objects(bucket_name, object_names, options = {}) + headers = options.dup + data = "" + data << "true" if headers.delete(:quiet) + version_ids = headers.delete('versionId') + object_names.each do |object_name| + data << "" + data << "#{CGI.escapeHTML(object_name)}" + object_version = version_ids.nil? ? nil : version_ids[object_name] + if object_version + data << "#{CGI.escapeHTML(object_version)}" + end + data << "" + end + data << "" + + headers['Content-Length'] = data.length + headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)). + gsub("\n", '') + + request({ + :body => data, + :expects => 200, + :headers => headers, + :bucket_name => bucket_name, + :method => 'POST', + :parser => Fog::Parsers::Storage::AWS::DeleteMultipleObjects.new, + :query => {'delete' => nil} + }) + end + end + + class Mock # :nodoc:all + def delete_multiple_objects(bucket_name, object_names, options = {}) + headers = options.dup + headers.delete(:quiet) + response = Excon::Response.new + if bucket = self.data[:buckets][bucket_name] + response.status = 200 + response.body = { 'DeleteResult' => [] } + version_ids = headers.delete('versionId') + object_names.each do |object_name| + object_version = version_ids.nil? ? nil : version_ids[object_name] + response.body['DeleteResult'] << delete_object_helper(bucket, + object_name, + object_version) + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + + private + + def delete_object_helper(bucket, object_name, version_id) + response = { 'Deleted' => {} } + if bucket[:versioning] + bucket[:objects][object_name] ||= [] + + if version_id + version = bucket[:objects][object_name].find { |object| object['VersionId'] == version_id} + + # S3 special cases the 'null' value to not error out if no such version exists. + if version || (version_id == 'null') + bucket[:objects][object_name].delete(version) + bucket[:objects].delete(object_name) if bucket[:objects][object_name].empty? + + response['Deleted'] = { 'Key' => object_name, + 'VersionId' => version_id, + 'DeleteMarker' => 'true', + 'DeleteMarkerVersionId' => version_id + } + else + response = delete_error_body(object_name, + version_id, + 'InvalidVersion', + 'Invalid version ID specified') + end + else + delete_marker = { + :delete_marker => true, + 'Key' => object_name, + 'VersionId' => bucket[:versioning] == 'Enabled' ? Fog::Mock.random_base64(32) : 'null', + 'Last-Modified' => Fog::Time.now.to_date_header + } + + # When versioning is suspended, a delete marker is placed if the last object ID is not the value 'null', + # otherwise the last object is replaced. + if bucket[:versioning] == 'Suspended' && bucket[:objects][object_name].first['VersionId'] == 'null' + bucket[:objects][object_name].shift + end + + bucket[:objects][object_name].unshift(delete_marker) + + response['Deleted'] = { 'Key' => object_name, + 'VersionId' => delete_marker['VersionId'], + 'DeleteMarkerVersionId' => + delete_marker['VersionId'], + 'DeleteMarker' => 'true', + } + end + else + if version_id && version_id != 'null' + response = delete_error_body(object_name, + version_id, + 'InvalidVersion', + 'Invalid version ID specified') + response = invalid_version_id_payload(version_id) + else + bucket[:objects].delete(object_name) + response['Deleted'] = { 'Key' => object_name } + end + end + response + end + + def delete_error_body(key, version_id, message, code) + { + 'Error' => { + 'Code' => code, + 'Message' => message, + 'VersionId' => version_id, + 'Key' => key, + } + } + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_object.rb b/lib/fog/aws/requests/storage/delete_object.rb new file mode 100644 index 000000000..f482d1abe --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_object.rb @@ -0,0 +1,115 @@ +module Fog + module Storage + class Aws + class Real + # Delete an object from S3 + # + # @param bucket_name [String] Name of bucket containing object to delete + # @param object_name [String] Name of object to delete + # + # @return [Excon::Response] response: + # * status [Integer] - 204 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectDELETE.html + + def delete_object(bucket_name, object_name, options = {}) + if version_id = options.delete('versionId') + query = {'versionId' => version_id} + else + query = {} + end + + headers = options + request({ + :expects => 204, + :headers => headers, + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'DELETE', + :query => query + }) + end + end + + class Mock # :nodoc:all + def delete_object(bucket_name, object_name, options = {}) + response = Excon::Response.new + if bucket = self.data[:buckets][bucket_name] + response.status = 204 + + version_id = options.delete('versionId') + + if bucket[:versioning] + bucket[:objects][object_name] ||= [] + + if version_id + version = bucket[:objects][object_name].find { |object| object['VersionId'] == version_id} + + # S3 special cases the 'null' value to not error out if no such version exists. + if version || (version_id == 'null') + bucket[:objects][object_name].delete(version) + bucket[:objects].delete(object_name) if bucket[:objects][object_name].empty? + + response.headers['x-amz-delete-marker'] = 'true' if version[:delete_marker] + response.headers['x-amz-version-id'] = version_id + else + response.status = 400 + response.body = invalid_version_id_payload(version_id) + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + else + delete_marker = { + :delete_marker => true, + 'Key' => object_name, + 'VersionId' => bucket[:versioning] == 'Enabled' ? Fog::Mock.random_base64(32) : 'null', + 'Last-Modified' => Fog::Time.now.to_date_header + } + + # When versioning is suspended, a delete marker is placed if the last object ID is not the value 'null', + # otherwise the last object is replaced. + if bucket[:versioning] == 'Suspended' && bucket[:objects][object_name].first['VersionId'] == 'null' + bucket[:objects][object_name].shift + end + + bucket[:objects][object_name].unshift(delete_marker) + + response.headers['x-amz-delete-marker'] = 'true' + response.headers['x-amz-version-id'] = delete_marker['VersionId'] + end + else + if version_id && version_id != 'null' + response.status = 400 + response.body = invalid_version_id_payload(version_id) + raise(Excon::Errors.status_error({:expects => 200}, response)) + else + bucket[:objects].delete(object_name) + + response.headers['x-amz-version-id'] = 'null' + end + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 204}, response)) + end + response + end + + private + + def invalid_version_id_payload(version_id) + { + 'Error' => { + 'Code' => 'InvalidArgument', + 'Message' => 'Invalid version id specified', + 'ArgumentValue' => version_id, + 'ArgumentName' => 'versionId', + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket.rb b/lib/fog/aws/requests/storage/get_bucket.rb new file mode 100644 index 000000000..2408fed8f --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket.rb @@ -0,0 +1,108 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket' + + # List information about objects in an S3 bucket + # + # @param bucket_name [String] name of bucket to list object keys from + # @param options [Hash] config arguments for list. Defaults to {}. + # @option options delimiter [String] causes keys with the same string between the prefix + # value and the first occurence of delimiter to be rolled up + # @option options marker [String] limits object keys to only those that appear + # lexicographically after its value. + # @option options max-keys [Integer] limits number of object keys returned + # @option options prefix [String] limits object keys to those beginning with its value. + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Delimeter [String] - Delimiter specified for query + # * IsTruncated [Boolean] - Whether or not the listing is truncated + # * Marker [String]- Marker specified for query + # * MaxKeys [Integer] - Maximum number of keys specified for query + # * Name [String] - Name of the bucket + # * Prefix [String] - Prefix specified for query + # * CommonPrefixes [Array] - Array of strings for common prefixes + # * Contents [Array]: + # * ETag [String] - Etag of object + # * Key [String] - Name of object + # * LastModified [String] - Timestamp of last modification of object + # * Owner [Hash]: + # * DisplayName [String] - Display name of object owner + # * ID [String] - Id of object owner + # * Size [Integer] - Size of object + # * StorageClass [String] - Storage class of object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGET.html + + def get_bucket(bucket_name, options = {}) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucket.new, + :query => options + }) + end + end + + class Mock # :nodoc:all + def get_bucket(bucket_name, options = {}) + prefix, marker, delimiter, max_keys = \ + options['prefix'], options['marker'], options['delimiter'], options['max-keys'] + common_prefixes = [] + + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + response = Excon::Response.new + if bucket = self.data[:buckets][bucket_name] + contents = bucket[:objects].values.map(&:first).sort {|x,y| x['Key'] <=> y['Key']}.reject do |object| + (prefix && object['Key'][0...prefix.length] != prefix) || + (marker && object['Key'] <= marker) || + (delimiter && object['Key'][(prefix ? prefix.length : 0)..-1].include?(delimiter) \ + && common_prefixes << object['Key'].sub(/^(#{prefix}[^#{delimiter}]+.).*/, '\1')) || + object.key?(:delete_marker) + end.map do |object| + data = object.reject {|key, value| !['ETag', 'Key', 'StorageClass'].include?(key)} + data.merge!({ + 'LastModified' => Time.parse(object['Last-Modified']), + 'Owner' => bucket['Owner'], + 'Size' => object['Content-Length'].to_i + }) + data + end + max_keys = max_keys || 1000 + size = [max_keys, 1000].min + truncated_contents = contents[0...size] + + response.status = 200 + response.body = { + 'CommonPrefixes' => common_prefixes.uniq, + 'Contents' => truncated_contents, + 'IsTruncated' => truncated_contents.size != contents.size, + 'Marker' => marker, + 'MaxKeys' => max_keys, + 'Name' => bucket['Name'], + 'Prefix' => prefix + } + if max_keys && max_keys < response.body['Contents'].length + response.body['IsTruncated'] = true + response.body['Contents'] = response.body['Contents'][0...max_keys] + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_acl.rb b/lib/fog/aws/requests/storage/get_bucket_acl.rb new file mode 100644 index 000000000..3530e84fa --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_acl.rb @@ -0,0 +1,65 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/access_control_list' + + # Get access control list for an S3 bucket + # + # @param bucket_name [String] name of bucket to get access control list for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * AccessControlPolicy [Hash]: + # * Owner [Hash]: + # * DisplayName [String] - Display name of object owner + # * ID [String] - Id of object owner + # * AccessControlList [Array]: + # * Grant [Hash]: + # * Grantee [Hash]: + # * DisplayName [String] - Display name of grantee + # * ID [String] - Id of grantee + # or + # * URI [String] - URI of group to grant access for + # * Permission [String] - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETacl.html + + def get_bucket_acl(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::AccessControlList.new, + :query => {'acl' => nil} + }) + end + end + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/acl_utils' + + def get_bucket_acl(bucket_name) + response = Excon::Response.new + if acl = self.data[:acls][:bucket][bucket_name] + response.status = 200 + if acl.is_a?(String) + response.body = Fog::Storage::AWS.acl_to_hash(acl) + else + response.body = acl + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_cors.rb b/lib/fog/aws/requests/storage/get_bucket_cors.rb new file mode 100644 index 000000000..82212137f --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_cors.rb @@ -0,0 +1,61 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/cors_configuration' + + # Gets the CORS configuration for an S3 bucket + # + # @param bucket_name [String] name of bucket to get access control list for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * CORSConfiguration [Array]: + # * CORSRule [Hash]: + # * AllowedHeader [String] - Which headers are allowed in a pre-flight OPTIONS request through the Access-Control-Request-Headers header. + # * AllowedMethod [String] - Identifies an HTTP method that the domain/origin specified in the rule is allowed to execute. + # * AllowedOrigin [String] - One or more response headers that you want customers to be able to access from their applications (for example, from a JavaScript XMLHttpRequest object). + # * ExposeHeader [String] - One or more headers in the response that you want customers to be able to access from their applications (for example, from a JavaScript XMLHttpRequest object). + # * ID [String] - An optional unique identifier for the rule. The ID value can be up to 255 characters long. The IDs help you find a rule in the configuration. + # * MaxAgeSeconds [Integer] - The time in seconds that your browser is to cache the preflight response for the specified resource. + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETcors.html + + def get_bucket_cors(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::CorsConfiguration.new, + :query => {'cors' => nil} + }) + end + end + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/cors_utils' + + def get_bucket_cors(bucket_name) + response = Excon::Response.new + if cors = self.data[:cors][:bucket][bucket_name] + response.status = 200 + if cors.is_a?(String) + response.body = Fog::Storage::AWS.cors_to_hash(cors) + else + response.body = cors + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_lifecycle.rb b/lib/fog/aws/requests/storage/get_bucket_lifecycle.rb new file mode 100644 index 000000000..182c0e06e --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_lifecycle.rb @@ -0,0 +1,35 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_lifecycle' + + # Get bucket lifecycle configuration + # + # @param bucket_name [String] name of bucket to get lifecycle configuration for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Rules - object expire rules [Array]: + # * ID [String] - Unique identifier for the rule + # * Prefix [String] - Prefix identifying one or more objects to which the rule applies + # * Enabled [Boolean] - if rule is currently being applied + # * Days [Integer] - lifetime, in days, of the objects that are subject to the rule + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlifecycle.html + + def get_bucket_lifecycle(bucket_name) + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketLifecycle.new, + :query => {'lifecycle' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_location.rb b/lib/fog/aws/requests/storage/get_bucket_location.rb new file mode 100644 index 000000000..382dbe76d --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_location.rb @@ -0,0 +1,55 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_location' + + # Get location constraint for an S3 bucket + # + # @param bucket_name [String] name of bucket to get location constraint for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * LocationConstraint [String] - Location constraint of the bucket + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlocation.html + + def get_bucket_location(bucket_name) + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketLocation.new, + :query => {'location' => nil}, + :path_style => true + }) + end + end + + class Mock # :nodoc:all + def get_bucket_location(bucket_name) + response = Excon::Response.new + if bucket = self.data[:buckets][bucket_name] + location_constraint = case bucket['LocationConstraint'] + when 'us-east-1' + nil + when 'eu-east-1' + 'EU' + else + bucket['LocationConstraint'] + end + + response.status = 200 + response.body = {'LocationConstraint' => location_constraint } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_logging.rb b/lib/fog/aws/requests/storage/get_bucket_logging.rb new file mode 100644 index 000000000..d16ef15b7 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_logging.rb @@ -0,0 +1,45 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_logging' + + # Get logging status for an S3 bucket + # + # @param bucket_name [String] name of bucket to get logging status for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * BucketLoggingStatus (will be empty if logging is disabled) [Hash]: + # * LoggingEnabled [Hash]: + # * TargetBucket [String] - bucket where logs are stored + # * TargetPrefix [String] - prefix logs are stored with + # * TargetGrants [Array]: + # * Grant [Hash]: + # * Grantee [Hash]: + # * DisplayName [String] - Display name of grantee + # * ID [String] - Id of grantee + # or + # * URI [String] - URI of group to grant access for + # * Permission [String] - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlogging.html + + def get_bucket_logging(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketLogging.new, + :query => {'logging' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_object_versions.rb b/lib/fog/aws/requests/storage/get_bucket_object_versions.rb new file mode 100644 index 000000000..13a4d5786 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_object_versions.rb @@ -0,0 +1,160 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_object_versions' + + # List information about object versions in an S3 bucket + # + # @param bucket_name [String] name of bucket to list object keys from + # @param options [Hash] config arguments for list + # @option options delimiter [String] causes keys with the same string between the prefix value and the first occurence of delimiter to be rolled up + # @option options key-marker [String] limits object keys to only those that appear lexicographically after its value. + # @option options max-keys [Integer] limits number of object keys returned + # @option options prefix [String] limits object keys to those beginning with its value. + # @option options version-id-marker [String] limits object versions to only those that appear lexicographically after its value + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Delimeter [String] - Delimiter specified for query + # * KeyMarker [String] - Key marker specified for query + # * MaxKeys [Integer] - Maximum number of keys specified for query + # * Name [String] - Name of the bucket + # * Prefix [String] - Prefix specified for query + # * VersionIdMarker [String] - Version id marker specified for query + # * IsTruncated [Boolean] - Whether or not this is the totality of the bucket + # * Versions [Array]: + # * DeleteMarker [Hash]: + # * IsLatest [Boolean] - Whether or not this is the latest version + # * Key [String] - Name of object + # * LastModified [String]: Timestamp of last modification of object + # * Owner [Hash]: + # * DisplayName [String] - Display name of object owner + # * ID [String] - Id of object owner + # * VersionId [String] - The id of this version + # or + # * Version [Hash]: + # * ETag [String]: Etag of object + # * IsLatest [Boolean] - Whether or not this is the latest version + # * Key [String] - Name of object + # * LastModified [String]: Timestamp of last modification of object + # * Owner [Hash]: + # * DisplayName [String] - Display name of object owner + # * ID [String] - Id of object owner + # * Size [Integer] - Size of object + # * StorageClass [String] - Storage class of object + # * VersionId [String] - The id of this version + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETVersion.html + + def get_bucket_object_versions(bucket_name, options = {}) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketObjectVersions.new, + :query => {'versions' => nil}.merge!(options) }) + end + end + + class Mock + def get_bucket_object_versions(bucket_name, options = {}) + delimiter, key_marker, max_keys, prefix, version_id_marker = \ + options['delimiter'], options['key-marker'], options['max-keys'],options['prefix'],options['version-id-marker'] + + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + + response = Excon::Response.new + + # Invalid arguments. + if version_id_marker && !key_marker + response.status = 400 + response.body = { + 'Error' => { + 'Code' => 'InvalidArgument', + 'Message' => 'A version-id marker cannot be specified without a key marker.', + 'ArgumentValue' => version_id_marker, + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + + # Valid case. + # TODO: (nirvdrum 12/15/11) It's not clear to me how to actually use version-id-marker, so I didn't implement it below. + elsif bucket = self.data[:buckets][bucket_name] + # We need to order results by S3 key, but since our data store is key => [versions], we want to ensure the integrity + # of the versions as well. So, sort the keys, then fetch the versions, and then combine them all as a sorted list by + # flattening the results. + contents = bucket[:objects].keys.sort.map { |key| bucket[:objects][key] }.flatten.reject do |object| + (prefix && object['Key'][0...prefix.length] != prefix) || + (key_marker && object['Key'] <= key_marker) || + (delimiter && object['Key'][(prefix ? prefix.length : 0)..-1].include?(delimiter) \ + && common_prefixes << object['Key'].sub(/^(#{prefix}[^#{delimiter}]+.).*/, '\1')) + end.map do |object| + if object.key?(:delete_marker) + tag_name = 'DeleteMarker' + extracted_attrs = ['Key', 'VersionId'] + else + tag_name = 'Version' + extracted_attrs = ['ETag', 'Key', 'StorageClass', 'VersionId'] + end + + data = {} + data[tag_name] = object.reject { |key, value| !extracted_attrs.include?(key) } + data[tag_name].merge!({ + 'LastModified' => Time.parse(object['Last-Modified']), + 'Owner' => bucket['Owner'], + 'IsLatest' => object == bucket[:objects][object['Key']].first + }) + + data[tag_name]['Size'] = object['Content-Length'].to_i if tag_name == 'Version' + data + end + + max_keys = max_keys || 1000 + size = [max_keys, 1000].min + truncated_contents = contents[0...size] + + response.status = 200 + response.body = { + 'Versions' => truncated_contents, + 'IsTruncated' => truncated_contents.size != contents.size, + 'KeyMarker' => key_marker, + 'VersionIdMarker' => version_id_marker, + 'MaxKeys' => max_keys, + 'Name' => bucket['Name'], + 'Prefix' => prefix + } + if max_keys && max_keys < response.body['Versions'].length + response.body['IsTruncated'] = true + response.body['Versions'] = response.body['Versions'][0...max_keys] + end + + # Missing bucket case. + else + response.status = 404 + response.body = { + 'Error' => { + 'Code' => 'NoSuchBucket', + 'Message' => 'The specified bucket does not exist', + 'BucketName' => bucket_name, + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_policy.rb b/lib/fog/aws/requests/storage/get_bucket_policy.rb new file mode 100644 index 000000000..6d9689f6d --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_policy.rb @@ -0,0 +1,31 @@ +module Fog + module Storage + class Aws + class Real + # Get bucket policy for an S3 bucket + # + # @param bucket_name [String] name of bucket to get policy for + # + # @return [Excon::Response] response: + # * body [Hash] - policy document + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETpolicy.html + + def get_bucket_policy(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + response = request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :query => {'policy' => nil} + }) + response.body = Fog::JSON.decode(response.body) unless response.body.nil? + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_tagging.rb b/lib/fog/aws/requests/storage/get_bucket_tagging.rb new file mode 100644 index 000000000..20a8d70d2 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_tagging.rb @@ -0,0 +1,49 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_tagging' + + # Get tags for an S3 bucket + # + # @param bucket_name [String] name of bucket to get tags for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * BucketTagging [Hash]: + # * Key [String] - tag key + # * Value [String] - tag value + # @see http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETtagging.html + + def get_bucket_tagging(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketTagging.new, + :query => {'tagging' => nil} + }) + end + end + + class Mock # :nodoc:all + def get_bucket_tagging(bucket_name) + response = Excon::Response.new + if self.data[:buckets][bucket_name] && self.data[:bucket_tagging][bucket_name] + response.status = 200 + response.body = {'BucketTagging' => self.data[:bucket_tagging][bucket_name]} + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_versioning.rb b/lib/fog/aws/requests/storage/get_bucket_versioning.rb new file mode 100644 index 000000000..722413193 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_versioning.rb @@ -0,0 +1,68 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_versioning' + + # Get versioning status for an S3 bucket + # + # @param bucket_name [String] name of bucket to get versioning status for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * VersioningConfiguration [Hash]: + # * Status [String] - Versioning status in ['Enabled', 'Suspended', nil] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETversioningStatus.html + + def get_bucket_versioning(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketVersioning.new, + :query => {'versioning' => nil} + }) + end + end + + class Mock + def get_bucket_versioning(bucket_name) + response = Excon::Response.new + bucket = self.data[:buckets][bucket_name] + + if bucket + response.status = 200 + + if bucket[:versioning] + response.body = { 'VersioningConfiguration' => { 'Status' => bucket[:versioning] } } + else + response.body = { 'VersioningConfiguration' => {} } + end + + else + response.status = 404 + response.body = { + 'Error' => { + 'Code' => 'NoSuchBucket', + 'Message' => 'The specified bucket does not exist', + 'BucketName' => bucket_name, + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_website.rb b/lib/fog/aws/requests/storage/get_bucket_website.rb new file mode 100644 index 000000000..26b917b84 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_website.rb @@ -0,0 +1,38 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_bucket_website' + + # Get website configuration for an S3 bucket + # + # + # @param bucket_name [String] name of bucket to get website configuration for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * IndexDocument [Hash]: + # * Suffix [String] - Suffix appended when directory is requested + # * ErrorDocument [Hash]: + # * Key [String] - Object key to return for 4XX class errors + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETwebsite.html + + def get_bucket_website(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketWebsite.new, + :query => {'website' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_object.rb b/lib/fog/aws/requests/storage/get_object.rb new file mode 100644 index 000000000..60c5ab8b4 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_object.rb @@ -0,0 +1,189 @@ +module Fog + module Storage + class Aws + class Real + # Get an object from S3 + # + # @param bucket_name [String] Name of bucket to read from + # @param object_name [String] Name of object to read + # @param options [Hash] + # @option options If-Match [String] Returns object only if its etag matches this value, otherwise returns 412 (Precondition Failed). + # @option options If-Modified-Since [Time] Returns object only if it has been modified since this time, otherwise returns 304 (Not Modified). + # @option options If-None-Match [String] Returns object only if its etag differs from this value, otherwise returns 304 (Not Modified) + # @option options If-Unmodified-Since [Time] Returns object only if it has not been modified since this time, otherwise returns 412 (Precodition Failed). + # @option options Range [String] Range of object to download + # @option options versionId [String] specify a particular version to retrieve + # @option options query[Hash] specify additional query string + # + # @return [Excon::Response] response: + # * body [String]- Contents of object + # * headers [Hash]: + # * Content-Length [String] - Size of object contents + # * Content-Type [String] - MIME type of object + # * ETag [String] - Etag of object + # * Last-Modified [String] - Last modified timestamp for object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html + + def get_object(bucket_name, object_name, options = {}, &block) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + unless object_name + raise ArgumentError.new('object_name is required') + end + + params = { :headers => {} } + + params[:query] = options.delete('query') || {} + + if version_id = options.delete('versionId') + params[:query] = params[:query].merge({'versionId' => version_id}) + end + params[:headers].merge!(options) + if options['If-Modified-Since'] + params[:headers]['If-Modified-Since'] = Fog::Time.at(options['If-Modified-Since'].to_i).to_date_header + end + if options['If-Unmodified-Since'] + params[:headers]['If-Unmodified-Since'] = Fog::Time.at(options['If-Unmodified-Since'].to_i).to_date_header + end + + if block_given? + params[:response_block] = Proc.new + end + + request(params.merge!({ + :expects => [ 200, 206 ], + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'GET', + })) + end + end + + class Mock # :nodoc:all + def get_object(bucket_name, object_name, options = {}, &block) + version_id = options.delete('versionId') + + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + + unless object_name + raise ArgumentError.new('object_name is required') + end + + response = Excon::Response.new + if (bucket = self.data[:buckets][bucket_name]) + object = nil + if bucket[:objects].key?(object_name) + object = version_id ? bucket[:objects][object_name].find { |object| object['VersionId'] == version_id} : bucket[:objects][object_name].first + end + + if (object && !object[:delete_marker]) + if options['If-Match'] && options['If-Match'] != object['ETag'] + response.status = 412 + elsif options['If-Modified-Since'] && options['If-Modified-Since'] >= Time.parse(object['Last-Modified']) + response.status = 304 + elsif options['If-None-Match'] && options['If-None-Match'] == object['ETag'] + response.status = 304 + elsif options['If-Unmodified-Since'] && options['If-Unmodified-Since'] < Time.parse(object['Last-Modified']) + response.status = 412 + else + response.status = 200 + for key, value in object + case key + when 'Cache-Control', 'Content-Disposition', 'Content-Encoding', 'Content-Length', 'Content-MD5', 'Content-Type', 'ETag', 'Expires', 'Last-Modified', /^x-amz-meta-/ + response.headers[key] = value + end + end + + response.headers['x-amz-version-id'] = object['VersionId'] if bucket[:versioning] + + body = object[:body] + if options['Range'] + # since Aws S3 itself does not support multiple range headers, we will use only the first + ranges = byte_ranges(options['Range'], body.size) + unless ranges.nil? || ranges.empty? + response.status = 206 + body = body[ranges.first] + end + end + + unless block_given? + response.body = body + else + data = StringIO.new(body) + remaining = data.length + while remaining > 0 + chunk = data.read([remaining, Excon::CHUNK_SIZE].min) + block.call(chunk) + remaining -= Excon::CHUNK_SIZE + end + end + end + elsif version_id && !object + response.status = 400 + response.body = { + 'Error' => { + 'Code' => 'InvalidArgument', + 'Message' => 'Invalid version id specified', + 'ArgumentValue' => version_id, + 'ArgumentName' => 'versionId', + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + + raise(Excon::Errors.status_error({:expects => 200}, response)) + else + response.status = 404 + response.body = "...NoSuchKey<\/Code>..." + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + else + response.status = 404 + response.body = "...NoSuchBucket..." + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + + private + + # === Borrowed from rack + # Parses the "Range:" header, if present, into an array of Range objects. + # Returns nil if the header is missing or syntactically invalid. + # Returns an empty array if none of the ranges are satisfiable. + def byte_ranges(http_range, size) + # See + return nil unless http_range + ranges = [] + http_range.split(/,\s*/).each do |range_spec| + matches = range_spec.match(/bytes=(\d*)-(\d*)/) + return nil unless matches + r0,r1 = matches[1], matches[2] + if r0.empty? + return nil if r1.empty? + # suffix-byte-range-spec, represents trailing suffix of file + r0 = [size - r1.to_i, 0].max + r1 = size - 1 + else + r0 = r0.to_i + if r1.empty? + r1 = size - 1 + else + r1 = r1.to_i + return nil if r1 < r0 # backwards range is syntactically invalid + r1 = size-1 if r1 >= size + end + end + ranges << (r0..r1) if r0 <= r1 + end + ranges + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_object_acl.rb b/lib/fog/aws/requests/storage/get_object_acl.rb new file mode 100644 index 000000000..0f0be4edc --- /dev/null +++ b/lib/fog/aws/requests/storage/get_object_acl.rb @@ -0,0 +1,76 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/access_control_list' + + # Get access control list for an S3 object + # + # @param bucket_name [String] name of bucket containing object + # @param object_name [String] name of object to get access control list for + # @param options [Hash] + # @option options versionId [String] specify a particular version to retrieve + # + # @return [Excon::Response] response: + # * body [Hash]: + # * [AccessControlPolicy [Hash]: + # * Owner [Hash]: + # * DisplayName [String] - Display name of object owner + # * ID [String] - Id of object owner + # * AccessControlList [Array]: + # * Grant [Hash]: + # * Grantee [Hash]: + # * DisplayName [String] - Display name of grantee + # * ID [String] - Id of grantee + # or + # * URI [String] - URI of group to grant access for + # * Permission [String] - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETacl.html + + def get_object_acl(bucket_name, object_name, options = {}) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + unless object_name + raise ArgumentError.new('object_name is required') + end + query = {'acl' => nil} + if version_id = options.delete('versionId') + query['versionId'] = version_id + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::AccessControlList.new, + :query => query + }) + end + end + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/acl_utils' + + def get_object_acl(bucket_name, object_name, options = {}) + response = Excon::Response.new + if acl = self.data[:acls][:object][bucket_name] && self.data[:acls][:object][bucket_name][object_name] + response.status = 200 + if acl.is_a?(String) + response.body = Fog::Storage::AWS.acl_to_hash(acl) + else + response.body = acl + end + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_object_http_url.rb b/lib/fog/aws/requests/storage/get_object_http_url.rb new file mode 100644 index 000000000..f63745083 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_object_http_url.rb @@ -0,0 +1,30 @@ +module Fog + module Storage + class Aws + module GetObjectHttpUrl + def get_object_http_url(bucket_name, object_name, expires, options = {}) + get_object_url(bucket_name, object_name, expires, options.merge(:scheme => 'http')) + end + end + + class Real + # Get an expiring object http url from S3 + # + # @param bucket_name [String] Name of bucket containing object + # @param object_name [String] Name of object to get expiring url for + # @param expires [Time] An expiry time for this url + # + # @return [Excon::Response] response: + # * body [String] - url for object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html + + include GetObjectHttpUrl + end + + class Mock # :nodoc:all + include GetObjectHttpUrl + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_object_https_url.rb b/lib/fog/aws/requests/storage/get_object_https_url.rb new file mode 100644 index 000000000..4137d82e6 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_object_https_url.rb @@ -0,0 +1,30 @@ +module Fog + module Storage + class Aws + module GetObjectHttpsUrl + def get_object_https_url(bucket_name, object_name, expires, options = {}) + get_object_url(bucket_name, object_name, expires, options.merge(:scheme => 'https')) + end + end + + class Real + # Get an expiring object https url from S3 + # + # @param bucket_name [String] Name of bucket containing object + # @param object_name [String] Name of object to get expiring url for + # @param expires [Time] An expiry time for this url + # + # @return [Excon::Response] response: + # * body [String] - url for object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html + + include GetObjectHttpsUrl + end + + class Mock # :nodoc:all + include GetObjectHttpsUrl + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_object_torrent.rb b/lib/fog/aws/requests/storage/get_object_torrent.rb new file mode 100644 index 000000000..9677bf726 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_object_torrent.rb @@ -0,0 +1,45 @@ +module Fog + module Storage + class Aws + class Real + # Get torrent for an S3 object + # + # @param bucket_name [String] name of bucket containing object + # @param object_name [String] name of object to get torrent for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * AccessControlPolicy [Hash: + # * Owner [Hash]: + # * DisplayName [String] - Display name of object owner + # * ID [String] - Id of object owner + # * AccessControlList [Array]: + # * Grant [Hash]: + # * Grantee [Hash]: + # * DisplayName [String] - Display name of grantee + # * ID [String] - Id of grantee + # * Permission [String] - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETtorrent.html + + def get_object_torrent(bucket_name, object_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + unless object_name + raise ArgumentError.new('object_name is required') + end + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'GET', + :query => {'torrent' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_object_url.rb b/lib/fog/aws/requests/storage/get_object_url.rb new file mode 100644 index 000000000..a0e324f52 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_object_url.rb @@ -0,0 +1,40 @@ +module Fog + module Storage + class Aws + module GetObjectUrl + def get_object_url(bucket_name, object_name, expires, options = {}) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + unless object_name + raise ArgumentError.new('object_name is required') + end + signed_url(options.merge({ + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'GET' + }), expires) + end + end + + class Real + # Get an expiring object url from S3 + # + # @param bucket_name [String] Name of bucket containing object + # @param object_name [String] Name of object to get expiring url for + # @param expires [Time] An expiry time for this url + # + # @return [Excon::Response] response: + # * body [String] - url for object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html + + include GetObjectUrl + end + + class Mock # :nodoc:all + include GetObjectUrl + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_request_payment.rb b/lib/fog/aws/requests/storage/get_request_payment.rb new file mode 100644 index 000000000..439286167 --- /dev/null +++ b/lib/fog/aws/requests/storage/get_request_payment.rb @@ -0,0 +1,45 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_request_payment' + + # Get configured payer for an S3 bucket + # + # @param bucket_name [String] name of bucket to get payer for + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Payer [String] - Specifies who pays for download and requests + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentGET.html + + def get_request_payment(bucket_name) + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetRequestPayment.new, + :query => {'requestPayment' => nil} + }) + end + end + + class Mock # :nodoc:all + def get_request_payment(bucket_name) + response = Excon::Response.new + if bucket = self.data[:buckets][bucket_name] + response.status = 200 + response.body = { 'Payer' => bucket['Payer'] } + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_service.rb b/lib/fog/aws/requests/storage/get_service.rb new file mode 100644 index 000000000..93d4d342b --- /dev/null +++ b/lib/fog/aws/requests/storage/get_service.rb @@ -0,0 +1,50 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/get_service' + + # List information about S3 buckets for authorized user + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Buckets [Hash]: + # * Name [String] - Name of bucket + # * CreationTime [Time] - Timestamp of bucket creation + # * Owner [Hash]: + # * DisplayName [String] - Display name of bucket owner + # * ID [String] - Id of bucket owner + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTServiceGET.html + # + def get_service + request({ + :expects => 200, + :headers => {}, + :host => @host, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetService.new + }) + end + end + + class Mock # :nodoc:all + def get_service + response = Excon::Response.new + response.headers['Status'] = 200 + buckets = self.data[:buckets].values.map do |bucket| + bucket.reject do |key, value| + !['CreationDate', 'Name'].include?(key) + end + end + response.body = { + 'Buckets' => buckets, + 'Owner' => { 'DisplayName' => 'owner', 'ID' => 'some_id'} + } + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/head_bucket.rb b/lib/fog/aws/requests/storage/head_bucket.rb new file mode 100644 index 000000000..57768bf0d --- /dev/null +++ b/lib/fog/aws/requests/storage/head_bucket.rb @@ -0,0 +1,38 @@ +module Fog + module Storage + class Aws + class Real + # Get headers for an S3 bucket, used to verify if it exists and if you have permission to access it + # + # @param bucket_name [String] Name of bucket to read from + # + # @return [Excon::Response] 200 response implies it exists, 404 does not exist, 403 no permissions + # * body [String] Empty + # * headers [Hash]: + # * Content-Type [String] - MIME type of object + # + # @see http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketHEAD.html + # + def head_bucket(bucket_name) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + request({ + :expects => 200, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'HEAD', + }) + end + end + + class Mock # :nodoc:all + def head_bucket(bucket_name) + response = get_bucket(bucket_name) + response.body = nil + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/head_object.rb b/lib/fog/aws/requests/storage/head_object.rb new file mode 100644 index 000000000..63fff920b --- /dev/null +++ b/lib/fog/aws/requests/storage/head_object.rb @@ -0,0 +1,62 @@ +module Fog + module Storage + class Aws + class Real + # Get headers for an object from S3 + # + # @param bucket_name [String] Name of bucket to read from + # @param object_name [String] Name of object to read + # @param options [Hash]: + # @option options [String] If-Match Returns object only if its etag matches this value, otherwise returns 412 (Precondition Failed). + # @option options [Time] If-Modified-Since Returns object only if it has been modified since this time, otherwise returns 304 (Not Modified). + # @option options [String] If-None-Match Returns object only if its etag differs from this value, otherwise returns 304 (Not Modified) + # @option options [Time] If-Unmodified-Since Returns object only if it has not been modified since this time, otherwise returns 412 (Precodition Failed). + # @option options [String] Range Range of object to download + # @option options [String] versionId specify a particular version to retrieve + # + # @return [Excon::Response] response: + # * body [String] Contents of object + # * headers [Hash]: + # * Content-Length [String] - Size of object contents + # * Content-Type [String] - MIME type of object + # * ETag [String] - Etag of object + # * Last-Modified - [String] Last modified timestamp for object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectHEAD.html + # + def head_object(bucket_name, object_name, options={}) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + unless object_name + raise ArgumentError.new('object_name is required') + end + if version_id = options.delete('versionId') + query = {'versionId' => version_id} + end + headers = {} + headers['If-Modified-Since'] = Fog::Time.at(options['If-Modified-Since'].to_i).to_date_header if options['If-Modified-Since'] + headers['If-Unmodified-Since'] = Fog::Time.at(options['If-Unmodified-Since'].to_i).to_date_header if options['If-Modified-Since'] + headers.merge!(options) + request({ + :expects => 200, + :headers => headers, + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'HEAD', + :query => query + }) + end + end + + class Mock # :nodoc:all + def head_object(bucket_name, object_name, options = {}) + response = get_object(bucket_name, object_name, options) + response.body = nil + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/initiate_multipart_upload.rb b/lib/fog/aws/requests/storage/initiate_multipart_upload.rb new file mode 100644 index 000000000..c0d044597 --- /dev/null +++ b/lib/fog/aws/requests/storage/initiate_multipart_upload.rb @@ -0,0 +1,66 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/initiate_multipart_upload' + + # Initiate a multipart upload to an S3 bucket + # + # @param bucket_name [String] Name of bucket to create object in + # @param object_name [String] Name of object to create + # @param options [Hash]: + # @option options [String] Cache-Control Caching behaviour + # @option options [String] Content-Disposition Presentational information for the object + # @option options [String] Content-Encoding Encoding of object data + # @option options [String] Content-MD5 Base64 encoded 128-bit MD5 digest of message (defaults to Base64 encoded MD5 of object.read) + # @option options [String] Content-Type Standard MIME type describing contents (defaults to MIME::Types.of.first) + # @option options [String] x-amz-acl Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read'] + # @option options [String] x-amz-meta-#{name} Headers to be returned with object, note total size of request without body must be less than 8 KB. + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Bucket [String] - Bucket where upload was initiated + # * Key [String] - Object key where the upload was initiated + # * UploadId [String] - Id for initiated multipart upload + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadInitiate.html + # + def initiate_multipart_upload(bucket_name, object_name, options = {}) + request({ + :expects => 200, + :headers => options, + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'POST', + :parser => Fog::Parsers::Storage::AWS::InitiateMultipartUpload.new, + :query => {'uploads' => nil} + }) + end + end # Real + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/shared_mock_methods' + include Fog::Storage::AWS::SharedMockMethods + + def initiate_multipart_upload(bucket_name, object_name, options = {}) + verify_mock_bucket_exists(bucket_name) + upload_id = UUID.uuid + self.data[:multipart_uploads][bucket_name] ||= {} + self.data[:multipart_uploads][bucket_name][upload_id] = { + :parts => {}, + :options => options, + } + + response = Excon::Response.new + response.status = 200 + response.body = { + "Bucket" => bucket_name, + "Key" => object_name, + "UploadId" => upload_id, + } + response + end + end # Mock + end # Storage + end # Aws +end # Fog diff --git a/lib/fog/aws/requests/storage/list_multipart_uploads.rb b/lib/fog/aws/requests/storage/list_multipart_uploads.rb new file mode 100644 index 000000000..bb8b3dcd4 --- /dev/null +++ b/lib/fog/aws/requests/storage/list_multipart_uploads.rb @@ -0,0 +1,52 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/list_multipart_uploads' + + # List multipart uploads for a bucket + # + # @param [String] bucket_name Name of bucket to list multipart uploads for + # @param [Hash] options config arguments for list. Defaults to {}. + # @option options [String] key-marker limits parts to only those that appear lexicographically after this key. + # @option options [Integer] max-uploads limits number of uploads returned + # @option options [String] upload-id-marker limits uploads to only those that appear lexicographically after this upload id. + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Bucket [String] Bucket where the multipart upload was initiated + # * IsTruncated [Boolean] Whether or not the listing is truncated + # * KeyMarker [String] first key in list, only upload ids after this lexographically will appear + # * MaxUploads [Integer] Maximum results to return + # * NextKeyMarker [String] last key in list, for further pagination + # * NextUploadIdMarker [String] last key in list, for further pagination + # * Upload [Hash]: + # * Initiated [Time] Time when upload was initiated + # * Initiator [Hash]: + # * DisplayName [String] Display name of upload initiator + # * ID [String] Id of upload initiator + # * Key [String] Key where multipart upload was initiated + # * Owner [Hash]: + # * DisplayName [String] Display name of upload owner + # * ID [String] Id of upload owner + # * StorageClass [String] Storage class of object + # * UploadId [String] upload id of upload containing part + # * UploadIdMarker [String] first key in list, only upload ids after this lexographically will appear + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListMPUpload.html + # + def list_multipart_uploads(bucket_name, options = {}) + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::ListMultipartUploads.new, + :query => options.merge!({'uploads' => nil}) + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/list_parts.rb b/lib/fog/aws/requests/storage/list_parts.rb new file mode 100644 index 000000000..9387c8ee6 --- /dev/null +++ b/lib/fog/aws/requests/storage/list_parts.rb @@ -0,0 +1,53 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/parsers/storage/list_parts' + + # List parts for a multipart upload + # + # @param bucket_name [String] Name of bucket to list parts for + # @param object_name [String] Name of object to list parts for + # @param upload_id [String] upload id to list objects for + # @param options [Hash] config arguments for list. Defaults to {}. + # @option options max-parts [Integer] limits number of parts returned + # @option options part-number-marker [String] limits parts to only those that appear lexicographically after this part number. + # + # @return [Excon::Response] response: + # * body [Hash]: + # * Bucket [string] Bucket where the multipart upload was initiated + # * Initiator [Hash]: + # * DisplayName [String] Display name of upload initiator + # * ID [String] Id of upload initiator + # * IsTruncated [Boolean] Whether or not the listing is truncated + # * Key [String] Key where multipart upload was initiated + # * MaxParts [String] maximum number of replies alllowed in response + # * NextPartNumberMarker [String] last item in list, for further pagination + # * Part [Array]: + # * ETag [String] ETag of part + # * LastModified [Timestamp] Last modified for part + # * PartNumber [String] Part number for part + # * Size [Integer] Size of part + # * PartNumberMarker [String] Part number after which listing begins + # * StorageClass [String] Storage class of object + # * UploadId [String] upload id of upload containing part + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListParts.html + # + def list_parts(bucket_name, object_name, upload_id, options = {}) + options['uploadId'] = upload_id + request({ + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::ListParts.new, + :query => options.merge!({'uploadId' => upload_id}) + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/post_object_hidden_fields.rb b/lib/fog/aws/requests/storage/post_object_hidden_fields.rb new file mode 100644 index 000000000..4ce7e3a6c --- /dev/null +++ b/lib/fog/aws/requests/storage/post_object_hidden_fields.rb @@ -0,0 +1,54 @@ +module Fog + module Storage + class Aws + class Real + # Get a hash of hidden fields for form uploading to S3, in the form {:field_name => :field_value} + # Form should look like:
+ # These hidden fields should then appear, followed by a field named 'file' which is either a textarea or file input. + # + # @param options Hash: + # @option options acl [String] access control list, in ['private', 'public-read', 'public-read-write', 'authenticated-read', 'bucket-owner-read', 'bucket-owner-full-control'] + # @option options Cache-Control [String] same as REST header + # @option options Content-Type [String] same as REST header + # @option options Content-Disposition [String] same as REST header + # @option options Content-Encoding [String] same as REST header + # @option options Expires same as REST header + # @option options key key for object, set to '${filename}' to use filename provided by user + # @option options policy security policy for upload + # @option options success_action_redirect url to redirct to upon success + # @option options success_action_status status code to return on success, in [200, 201, 204] + # @option options x-amz-security token devpay security token + # @option options x-amz-meta... meta data tags + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/HTTPPOSTForms.html + # + def post_object_hidden_fields(options = {}) + options = options.dup + if policy = options['policy'] + date = Fog::Time.now + credential = "#{@aws_access_key_id}/#{@signer.credential_scope(date)}" + extra_conditions = [ + {'x-amz-date' => date.to_iso8601_basic}, + {'x-amz-credential' => credential}, + {'x-amz-algorithm' => Fog::AWS::SignatureV4::ALGORITHM} + ] + + extra_conditions << {'x-amz-security-token' => @aws_session_token } if @aws_session_token + + policy_with_auth_fields = policy.merge('conditions' => policy['conditions'] + extra_conditions) + + options['policy'] = Base64.encode64(Fog::JSON.encode(policy_with_auth_fields)).gsub("\n", "") + options['X-Amz-Credential'] = credential + options['X-Amz-Date'] = date.to_iso8601_basic + options['X-Amz-Algorithm'] = Fog::AWS::SignatureV4::ALGORITHM + if @aws_session_token + options['X-Amz-Security-Token'] = @aws_session_token + end + options['X-Amz-Signature'] = @signer.derived_hmac(date).sign(options['policy']).unpack('H*').first + end + options + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/post_object_restore.rb b/lib/fog/aws/requests/storage/post_object_restore.rb new file mode 100644 index 000000000..917a4fffd --- /dev/null +++ b/lib/fog/aws/requests/storage/post_object_restore.rb @@ -0,0 +1,50 @@ +module Fog + module Storage + class Aws + class Real + # Restore an object from Glacier to its original S3 path + # + # @param bucket_name [String] Name of bucket containing object + # @param object_name [String] Name of object to restore + # @option days [Integer] Number of days to restore object for. Defaults to 100000 (a very long time) + # + # @return [Excon::Response] response: + # * status [Integer] 200 (OK) Object is previously restored + # * status [Integer] 202 (Accepted) Object is not previously restored + # * status [Integer] 409 (Conflict) Restore is already in progress + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPOSTrestore.html + # + def post_object_restore(bucket_name, object_name, days = 100000) + raise ArgumentError.new('bucket_name is required') unless bucket_name + raise ArgumentError.new('object_name is required') unless object_name + + data = '' + days.to_s + '' + + headers = {} + headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)).strip + headers['Content-Type'] = 'application/xml' + headers['Date'] = Fog::Time.now.to_date_header + + request({ + :headers => headers, + :bucket_name => bucket_name, + :expects => [200, 202, 409], + :body => data, + :method => 'POST', + :query => {'restore' => nil}, + :object_name => object_name + }) + end + end + + class Mock # :nodoc:all + def post_object_restore(bucket_name, object_name, days = 100000) + response = get_object(bucket_name, object_name) + response.body = nil + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket.rb b/lib/fog/aws/requests/storage/put_bucket.rb new file mode 100644 index 000000000..3248d5db1 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket.rb @@ -0,0 +1,73 @@ +module Fog + module Storage + class Aws + class Real + # Create an S3 bucket + # + # @param bucket_name [String] name of bucket to create + # @option options [Hash] config arguments for bucket. Defaults to {}. + # @option options LocationConstraint [Symbol] sets the location for the bucket + # @option options x-amz-acl [String] Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read'] + # + # @return [Excon::Response] response: + # * status [Integer] 200 + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html + # + def put_bucket(bucket_name, options = {}) + if location_constraint = options.delete('LocationConstraint') + data = +<<-DATA + + #{location_constraint} + +DATA + else + data = nil + end + request({ + :expects => 200, + :body => data, + :headers => options, + :idempotent => true, + :bucket_name => bucket_name, + :method => 'PUT' + }) + end + end + + class Mock # :nodoc:all + def put_bucket(bucket_name, options = {}) + acl = options['x-amz-acl'] || 'private' + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + else + self.data[:acls][:bucket][bucket_name] = self.class.acls(acl) + end + + response = Excon::Response.new + response.status = 200 + bucket = { + :objects => {}, + 'Name' => bucket_name, + 'CreationDate' => Time.now, + 'Owner' => { 'DisplayName' => 'owner', 'ID' => 'some_id'}, + 'Payer' => 'BucketOwner' + } + if options['LocationConstraint'] + bucket['LocationConstraint'] = options['LocationConstraint'] + else + bucket['LocationConstraint'] = nil + end + if !self.data[:buckets][bucket_name] || self.region == 'us-east-1' + self.data[:buckets][bucket_name] = bucket + else + response.status = 409 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_acl.rb b/lib/fog/aws/requests/storage/put_bucket_acl.rb new file mode 100644 index 000000000..b22c36604 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_acl.rb @@ -0,0 +1,69 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/requests/storage/acl_utils' + + # Change access control list for an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param acl [Hash] + # * Owner [Hash]: + # * ID [String]: id of owner + # * DisplayName [String]: display name of owner + # * AccessControlList [Array]: + # * Grantee [Hash]: + # * DisplayName [String] Display name of grantee + # * ID [String] Id of grantee + # or + # * EmailAddress [String] Email address of grantee + # or + # * URI [String] URI of group to grant access for + # * Permission [String] Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # * acl [String] Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read'] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTacl.html + + def put_bucket_acl(bucket_name, acl) + data = "" + headers = {} + + if acl.is_a?(Hash) + data = Fog::Storage::AWS.hash_to_acl(acl) + else + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + end + headers['x-amz-acl'] = acl + end + + headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)).strip + headers['Content-Type'] = 'application/json' + headers['Date'] = Fog::Time.now.to_date_header + + request({ + :body => data, + :expects => 200, + :headers => headers, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'acl' => nil} + }) + end + end + + class Mock + def put_bucket_acl(bucket_name, acl) + if acl.is_a?(Hash) + self.data[:acls][:bucket][bucket_name] = Fog::Storage::AWS.hash_to_acl(acl) + else + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + end + self.data[:acls][:bucket][bucket_name] = acl + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_cors.rb b/lib/fog/aws/requests/storage/put_bucket_cors.rb new file mode 100644 index 000000000..a9590ec0c --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_cors.rb @@ -0,0 +1,47 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/requests/storage/cors_utils' + + # Sets the cors configuration for your bucket. If the configuration exists, Amazon S3 replaces it. + # + # @param bucket_name [String] name of bucket to modify + # @param cors [Hash] + # * CORSConfiguration [Array]: + # * ID [String]: A unique identifier for the rule. + # * AllowedMethod [String]: An HTTP method that you want to allow the origin to execute. + # * AllowedOrigin [String]: An origin that you want to allow cross-domain requests from. + # * AllowedHeader [String]: Specifies which headers are allowed in a pre-flight OPTIONS request via the Access-Control-Request-Headers header. + # * MaxAgeSeconds [String]: The time in seconds that your browser is to cache the preflight response for the specified resource. + # * ExposeHeader [String]: One or more headers in the response that you want customers to be able to access from their applications. + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTcors.html + + def put_bucket_cors(bucket_name, cors) + data = Fog::Storage::AWS.hash_to_cors(cors) + + headers = {} + headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)).strip + headers['Content-Type'] = 'application/json' + headers['Date'] = Fog::Time.now.to_date_header + + request({ + :body => data, + :expects => 200, + :headers => headers, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'cors' => nil} + }) + end + end + + class Mock + def put_bucket_cors(bucket_name, cors) + self.data[:cors][:bucket][bucket_name] = Fog::Storage::AWS.hash_to_cors(cors) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_lifecycle.rb b/lib/fog/aws/requests/storage/put_bucket_lifecycle.rb new file mode 100644 index 000000000..5d3f1a972 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_lifecycle.rb @@ -0,0 +1,76 @@ +module Fog + module Storage + class Aws + class Real + # Change lifecycle configuration for an S3 bucket + # + # @param bucket_name [String] name of bucket to set lifecycle configuration for + # * lifecycle [Hash]: + # * Rules [Array] object expire rules + # * ID [String] Unique identifier for the rule + # * Prefix [String] Prefix identifying one or more objects to which the rule applies + # * Enabled [Boolean] if rule is currently being applied + # * Expiration [Hash] Container for the object expiration rule. + # * Days [Integer] lifetime, in days, of the objects that are subject to the rule + # * Date [Date] Indicates when the specific rule take effect. + # The date value must conform to the ISO 8601 format. The time is always midnight UTC. + # * Transition [Hash] Container for the transition rule that describes when objects transition + # to the Glacier storage class + # * Days [Integer] lifetime, in days, of the objects that are subject to the rule + # * Date [Date] Indicates when the specific rule take effect. + # The date value must conform to the ISO 8601 format. The time is always midnight UTC. + # * StorageClass [String] Indicates the Amazon S3 storage class to which you want the object + # to transition to. + # + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html + # + def put_bucket_lifecycle(bucket_name, lifecycle) + builder = Nokogiri::XML::Builder.new do + LifecycleConfiguration { + lifecycle['Rules'].each do |rule| + Rule { + ID rule['ID'] + Prefix rule['Prefix'] + Status rule['Enabled'] ? 'Enabled' : 'Disabled' + unless (rule['Expiration'] or rule['Transition']) + Expiration { Days rule['Days'] } + else + if rule['Expiration'] + if rule['Expiration']['Days'] + Expiration { Days rule['Expiration']['Days'] } + elsif rule['Expiration']['Date'] + Expiration { Date rule['Expiration']['Date'].is_a?(Time) ? rule['Expiration']['Date'].utc.iso8601 : Time.parse(rule['Expiration']['Date']).utc.iso8601 } + end + end + if rule['Transition'] + Transition { + if rule['Transition']['Days'] + Days rule['Transition']['Days'] + elsif rule['Transition']['Date'] + Date rule['Transition']['Date'].is_a?(Time) ? time.utc.iso8601 : Time.parse(time).utc.iso8601 + end + StorageClass rule['Transition']['StorageClass'].nil? ? 'GLACIER' : rule['Transition']['StorageClass'] + } + end + end + } + end + } + end + body = builder.to_xml + body.gsub! /<([^<>]+)\/>/, '<\1>' + request({ + :body => body, + :expects => 200, + :headers => {'Content-MD5' => Base64.encode64(Digest::MD5.digest(body)).chomp!, + 'Content-Type' => 'application/xml'}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'lifecycle' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_logging.rb b/lib/fog/aws/requests/storage/put_bucket_logging.rb new file mode 100644 index 000000000..eeb9aaedc --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_logging.rb @@ -0,0 +1,80 @@ +module Fog + module Storage + class Aws + class Real + # Change logging status for an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param logging_status [Hash]: + # * LoggingEnabled [Hash]: logging options or {} to disable + # * Owner [Hash]: + # * ID [String]: id of owner + # * DisplayName [String]: display name of owner + # * AccessControlList [Array]: + # * Grantee [Hash]: + # * DisplayName [String] Display name of grantee + # * ID [String] Id of grantee + # or + # * EmailAddress [String] Email address of grantee + # or + # * URI [String] URI of group to grant access for + # * Permission [String] Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlogging.html + + def put_bucket_logging(bucket_name, logging_status) + if logging_status['LoggingEnabled'].empty? + data = +<<-DATA + +DATA + else + data = +<<-DATA + + + #{logging_status['LoggingEnabled']['TargetBucket']} + #{logging_status['LoggingEnabled']['TargetBucket']} + +DATA + + logging_status['AccessControlList'].each do |grant| + data << " " + type = case grant['Grantee'].keys.sort + when ['DisplayName', 'ID'] + 'CanonicalUser' + when ['EmailAddress'] + 'AmazonCustomerByEmail' + when ['URI'] + 'Group' + end + data << " " + for key, value in grant['Grantee'] + data << " <#{key}>#{value}" + end + data << " " + data << " #{grant['Permission']}" + data << " " + end + + data << +<<-DATA + + + +DATA + end + + request({ + :body => data, + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'logging' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_policy.rb b/lib/fog/aws/requests/storage/put_bucket_policy.rb new file mode 100644 index 000000000..aa7155ad7 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_policy.rb @@ -0,0 +1,25 @@ +module Fog + module Storage + class Aws + class Real + # Change bucket policy for an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param policy [Hash] policy document + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTpolicy.html + + def put_bucket_policy(bucket_name, policy) + request({ + :body => Fog::JSON.encode(policy), + :expects => 204, + :headers => {}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'policy' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_tagging.rb b/lib/fog/aws/requests/storage/put_bucket_tagging.rb new file mode 100644 index 000000000..988d4f02a --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_tagging.rb @@ -0,0 +1,55 @@ +module Fog + module Storage + class Aws + class Real + # Change tag set for an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param tags [Hash]: + # * Key [String]: tag key + # * Value [String]: tag value + # + # @see http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTtagging.html + + def put_bucket_tagging(bucket_name, tags) + tagging = tags.map do |k,v| + "#{k}#{v}" + end.join("\n") + data = +<<-DATA + + + #{tagging} + + +DATA + + request({ + :body => data, + :expects => 204, + :headers => {'Content-MD5' => Base64.encode64(Digest::MD5.digest(data)).chomp!, 'Content-Type' => 'application/xml'}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'tagging' => nil} + }) + end + end + + class Mock # :nodoc:all + def put_bucket_tagging(bucket_name, tags) + response = Excon::Response.new + + if self.data[:buckets][bucket_name] + self.data[:bucket_tagging][bucket_name] = tags + response.status = 204 + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 204}, response)) + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_versioning.rb b/lib/fog/aws/requests/storage/put_bucket_versioning.rb new file mode 100644 index 000000000..b7e4c33ba --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_versioning.rb @@ -0,0 +1,74 @@ +module Fog + module Storage + class Aws + class Real + # Change versioning status for an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param status [String] Status to change to in ['Enabled', 'Suspended'] + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTVersioningStatus.html + + def put_bucket_versioning(bucket_name, status) + data = +<<-DATA + + #{status} + +DATA + + request({ + :body => data, + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'versioning' => nil} + }) + end + end + + class Mock + def put_bucket_versioning(bucket_name, status) + response = Excon::Response.new + bucket = self.data[:buckets][bucket_name] + + if bucket + if ['Enabled', 'Suspended'].include?(status) + bucket[:versioning] = status + + response.status = 200 + else + response.status = 400 + response.body = { + 'Error' => { + 'Code' => 'MalformedXML', + 'Message' => 'The XML you provided was not well-formed or did not validate against our published schema', + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + else + response.status = 404 + response.body = { + 'Error' => { + 'Code' => 'NoSuchBucket', + 'Message' => 'The specified bucket does not exist', + 'BucketName' => bucket_name, + 'RequestId' => Fog::Mock.random_hex(16), + 'HostId' => Fog::Mock.random_base64(65) + } + } + + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_bucket_website.rb b/lib/fog/aws/requests/storage/put_bucket_website.rb new file mode 100644 index 000000000..65c378818 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_website.rb @@ -0,0 +1,87 @@ +module Fog + module Storage + class Aws + class Real + # Change website configuration for an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param options [Hash] + # @option options RedirectAllRequestsTo [String] Host name to redirect all requests to - if this is set, other options are ignored + # @option options IndexDocument [String] suffix to append to requests for the bucket + # @option options ErrorDocument [String] key to use for 4XX class errors + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTwebsite.html + + def put_bucket_website(bucket_name, options, options_to_be_deprecated = {}) + options ||= {} + + # Method used to be called with the suffix as the second parameter. Warn user that this is not the case any more and move on + if options.is_a?(String) + Fog::Logger.deprecation("put_bucket_website with #{options.class} param is deprecated, use put_bucket_website('#{bucket_name}', :IndexDocument => '#{options}') instead [light_black](#{caller.first})[/]") + options = { :IndexDocument => options } + end + + # Parameter renamed from "key" to "ErrorDocument" + if options_to_be_deprecated[:key] + Fog::Logger.deprecation("put_bucket_website with three parameters is deprecated, use put_bucket_website('#{bucket_name}', :ErrorDocument => '#{options_to_be_deprecated[:key]}') instead [light_black](#{caller.first})[/]") + options[:ErrorDocument] = options_to_be_deprecated[:key] + end + + options.merge!(options_to_be_deprecated) { |key, o1, o2| o1 } + + data = "" + + if options[:RedirectAllRequestsTo] + # Redirect precludes all other options + data << <<-DATA + + #{options[:RedirectAllRequestsTo]} + + DATA + else + + if options[:IndexDocument] + data << <<-DATA + + #{options[:IndexDocument]} + + DATA + end + + if options[:ErrorDocument] + data << <<-DATA + + #{options[:ErrorDocument]} + + DATA + end + end + + data << '' + request({ + :body => data, + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'website' => nil} + }) + end + end + + class Mock # :nodoc:all + def put_bucket_website(bucket_name, suffix, options = {}) + response = Excon::Response.new + if self.data[:buckets][bucket_name] + response.status = 200 + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_object.rb b/lib/fog/aws/requests/storage/put_object.rb new file mode 100644 index 000000000..d89dd80e3 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_object.rb @@ -0,0 +1,87 @@ +module Fog + module Storage + class Aws + class Real + # Create an object in an S3 bucket + # + # @param bucket_name [String] Name of bucket to create object in + # @param object_name [String] Name of object to create + # @param data [File||String] File or String to create object from + # @param options [Hash] + # @option options Cache-Control [String] Caching behaviour + # @option options Content-Disposition [String] Presentational information for the object + # @option options Content-Encoding [String] Encoding of object data + # @option options Content-Length [String] Size of object in bytes (defaults to object.read.length) + # @option options Content-MD5 [String] Base64 encoded 128-bit MD5 digest of message + # @option options Content-Type [String] Standard MIME type describing contents (defaults to MIME::Types.of.first) + # @option options Expires [String] Cache expiry + # @option options x-amz-acl [String] Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read'] + # @option options x-amz-storage-class [String] Default is 'STANDARD', set to 'REDUCED_REDUNDANCY' for non-critical, reproducable data + # @option options x-amz-meta-#{name} Headers to be returned with object, note total size of request without body must be less than 8 KB. Each name, value pair must conform to US-ASCII. + # + # @return [Excon::Response] response: + # * headers [Hash]: + # * ETag [String] etag of new object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html + + def self.conforming_to_us_ascii!(keys, hash) + return if RUBY_VERSION =~ /^1\.8\./ + keys.each do |k| + v = hash[k] + if !v.encode(::Encoding::US_ASCII, :undef => :replace).eql?(v) + raise Excon::Errors::BadRequest.new("invalid #{k} header: value must be us-ascii") + end + end + end + + def put_object(bucket_name, object_name, data, options = {}) + data = Fog::Storage.parse_data(data) + headers = data[:headers].merge!(options) + self.class.conforming_to_us_ascii! headers.keys.grep(/^x-amz-meta-/), headers + + request({ + :body => data[:body], + :expects => 200, + :headers => headers, + :bucket_name => bucket_name, + :object_name => object_name, + :idempotent => true, + :method => 'PUT', + }) + end + end + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/shared_mock_methods' + include Fog::Storage::AWS::SharedMockMethods + + def put_object(bucket_name, object_name, data, options = {}) + define_mock_acl(bucket_name, object_name, options) + + data = parse_mock_data(data) + headers = data[:headers].merge!(options) + Fog::Storage::AWS::Real.conforming_to_us_ascii! headers.keys.grep(/^x-amz-meta-/), headers + bucket = verify_mock_bucket_exists(bucket_name) + + options['Content-Type'] ||= data[:headers]['Content-Type'] + options['Content-Length'] ||= data[:headers]['Content-Length'] + object = store_mock_object(bucket, object_name, data[:body], options) + + response = Excon::Response.new + response.status = 200 + + response.headers = { + 'Content-Length' => object['Content-Length'], + 'Content-Type' => object['Content-Type'], + 'ETag' => object['ETag'], + 'Last-Modified' => object['Last-Modified'], + } + + response.headers['x-amz-version-id'] = object['VersionId'] if object['VersionId'] != 'null' + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_object_acl.rb b/lib/fog/aws/requests/storage/put_object_acl.rb new file mode 100644 index 000000000..433c9c58e --- /dev/null +++ b/lib/fog/aws/requests/storage/put_object_acl.rb @@ -0,0 +1,78 @@ +module Fog + module Storage + class Aws + class Real + require 'fog/aws/requests/storage/acl_utils' + + # Change access control list for an S3 object + # + # @param [String] bucket_name name of bucket to modify + # @param [String] object_name name of object to get access control list for + # @param [Hash] acl + # * Owner [Hash] + # * ID [String] id of owner + # * DisplayName [String] display name of owner + # * AccessControlList [Array] + # * Grantee [Hash] + # * DisplayName [String] Display name of grantee + # * ID [String] Id of grantee + # or + # * EmailAddress [String] Email address of grantee + # or + # * URI [String] URI of group to grant access for + # * Permission [String] Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP] + # @param [String] acl Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read'] + # @param [Hash] options + # @option options [String] versionId specify a particular version to retrieve + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUTacl.html + + def put_object_acl(bucket_name, object_name, acl, options = {}) + query = {'acl' => nil} + if version_id = options.delete('versionId') + query['versionId'] = version_id + end + + data = "" + headers = {} + + if acl.is_a?(Hash) + data = Fog::Storage::AWS.hash_to_acl(acl) + else + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + end + headers['x-amz-acl'] = acl + end + + headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)).strip + headers['Content-Type'] = 'application/json' + headers['Date'] = Fog::Time.now.to_date_header + + request({ + :body => data, + :expects => 200, + :headers => headers, + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'PUT', + :query => query + }) + end + end + + class Mock + def put_object_acl(bucket_name, object_name, acl, options = {}) + if acl.is_a?(Hash) + self.data[:acls][:object][bucket_name][object_name] = Fog::Storage::AWS.hash_to_acl(acl) + else + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + end + self.data[:acls][:object][bucket_name][object_name] = acl + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_object_url.rb b/lib/fog/aws/requests/storage/put_object_url.rb new file mode 100644 index 000000000..016e6a946 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_object_url.rb @@ -0,0 +1,41 @@ +module Fog + module Storage + class Aws + module PutObjectUrl + def put_object_url(bucket_name, object_name, expires, headers = {}, options = {}) + unless bucket_name + raise ArgumentError.new('bucket_name is required') + end + unless object_name + raise ArgumentError.new('object_name is required') + end + signed_url(options.merge({ + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'PUT', + :headers => headers, + }), expires) + end + end + + class Real + # Get an expiring object url from S3 for putting an object + # + # @param bucket_name [String] Name of bucket containing object + # @param object_name [String] Name of object to get expiring url for + # @param expires [Time] An expiry time for this url + # + # @return [Excon::Response] response: + # * body [String] url for object + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html + + include PutObjectUrl + end + + class Mock # :nodoc:all + include PutObjectUrl + end + end + end +end diff --git a/lib/fog/aws/requests/storage/put_request_payment.rb b/lib/fog/aws/requests/storage/put_request_payment.rb new file mode 100644 index 000000000..1c6f52acb --- /dev/null +++ b/lib/fog/aws/requests/storage/put_request_payment.rb @@ -0,0 +1,45 @@ +module Fog + module Storage + class Aws + class Real + # Change who pays for requests to an S3 bucket + # + # @param bucket_name [String] name of bucket to modify + # @param payer [String] valid values are BucketOwner or Requester + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentPUT.html + + def put_request_payment(bucket_name, payer) + data = +<<-DATA + + #{payer} + +DATA + request({ + :body => data, + :expects => 200, + :headers => {}, + :bucket_name => bucket_name, + :method => 'PUT', + :query => {'requestPayment' => nil} + }) + end + end + + class Mock # :nodoc:all + def put_request_payment(bucket_name, payer) + response = Excon::Response.new + if bucket = self.data[:buckets][bucket_name] + response.status = 200 + bucket['Payer'] = payer + else + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + response + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/shared_mock_methods.rb b/lib/fog/aws/requests/storage/shared_mock_methods.rb new file mode 100644 index 000000000..6c4d41939 --- /dev/null +++ b/lib/fog/aws/requests/storage/shared_mock_methods.rb @@ -0,0 +1,87 @@ +module Fog + module Storage + class Aws + module SharedMockMethods + def define_mock_acl(bucket_name, object_name, options) + acl = options['x-amz-acl'] || 'private' + if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl) + raise Excon::Errors::BadRequest.new('invalid x-amz-acl') + else + self.data[:acls][:object][bucket_name] ||= {} + self.data[:acls][:object][bucket_name][object_name] = self.class.acls(acl) + end + end + + def parse_mock_data(data) + data = Fog::Storage.parse_data(data) + unless data[:body].is_a?(String) + data[:body] = data[:body].read + end + data + end + + def verify_mock_bucket_exists(bucket_name) + if (bucket = self.data[:buckets][bucket_name]) + return bucket + end + + response = Excon::Response.new + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + def get_upload_info(bucket_name, upload_id, delete = false) + if delete + upload_info = self.data[:multipart_uploads][bucket_name].delete(upload_id) + else + upload_info = self.data[:multipart_uploads][bucket_name][upload_id] + end + + if !upload_info + response = Excon::Response.new + response.status = 404 + raise(Excon::Errors.status_error({:expects => 200}, response)) + end + + upload_info + end + + def store_mock_object(bucket, object_name, body, options) + object = { + :body => body, + 'Content-Type' => options['Content-Type'], + 'ETag' => Digest::MD5.hexdigest(body), + 'Key' => object_name, + 'Last-Modified' => Fog::Time.now.to_date_header, + 'Content-Length' => options['Content-Length'], + 'StorageClass' => options['x-amz-storage-class'] || 'STANDARD', + 'VersionId' => bucket[:versioning] == 'Enabled' ? Fog::Mock.random_base64(32) : 'null' + } + + for key, value in options + case key + when 'Cache-Control', 'Content-Disposition', 'Content-Encoding', 'Content-MD5', 'Expires', /^x-amz-meta-/ + object[key] = value + end + end + + if bucket[:versioning] + bucket[:objects][object_name] ||= [] + + # When versioning is suspended, putting an object will create a new 'null' version if the latest version + # is a value other than 'null', otherwise it will replace the latest version. + if bucket[:versioning] == 'Suspended' && bucket[:objects][object_name].first['VersionId'] == 'null' + bucket[:objects][object_name].shift + end + + bucket[:objects][object_name].unshift(object) + else + bucket[:objects][object_name] = [object] + end + + object + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/sync_clock.rb b/lib/fog/aws/requests/storage/sync_clock.rb new file mode 100644 index 000000000..657c98775 --- /dev/null +++ b/lib/fog/aws/requests/storage/sync_clock.rb @@ -0,0 +1,24 @@ +module Fog + module Storage + class Aws + class Real + # Sync clock against S3 to avoid skew errors + # + def sync_clock + response = begin + get_service + rescue Excon::Errors::HTTPStatusError => error + error.response + end + Fog::Time.now = Time.parse(response.headers['Date']) + end + end # Real + + class Mock # :nodoc:all + def sync_clock + true + end + end # Mock + end # Storage + end # Aws +end # Fog diff --git a/lib/fog/aws/requests/storage/upload_part.rb b/lib/fog/aws/requests/storage/upload_part.rb new file mode 100644 index 000000000..297842491 --- /dev/null +++ b/lib/fog/aws/requests/storage/upload_part.rb @@ -0,0 +1,57 @@ +module Fog + module Storage + class Aws + class Real + # Upload a part for a multipart upload + # + # @param bucket_name [String] Name of bucket to add part to + # @param object_name [String] Name of object to add part to + # @param upload_id [String] Id of upload to add part to + # @param part_number [String] Index of part in upload + # @param data [File||String] Content for part + # @param options [Hash] + # @option options Content-MD5 [String] Base64 encoded 128-bit MD5 digest of message + # + # @return [Excon::Response] response + # * headers [Hash]: + # * ETag [String] etag of new object (will be needed to complete upload) + # + # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPart.html + # + def upload_part(bucket_name, object_name, upload_id, part_number, data, options = {}) + data = Fog::Storage.parse_data(data) + headers = options + headers['Content-Length'] = data[:headers]['Content-Length'] + request({ + :body => data[:body], + :expects => 200, + :idempotent => true, + :headers => headers, + :bucket_name => bucket_name, + :object_name => object_name, + :method => 'PUT', + :query => {'uploadId' => upload_id, 'partNumber' => part_number} + }) + end + end # Real + + class Mock # :nodoc:all + require 'fog/aws/requests/storage/shared_mock_methods' + include Fog::Storage::AWS::SharedMockMethods + + def upload_part(bucket_name, object_name, upload_id, part_number, data, options = {}) + data = parse_mock_data(data) + verify_mock_bucket_exists(bucket_name) + upload_info = get_upload_info(bucket_name, upload_id) + upload_info[:parts][part_number] = data[:body] + + response = Excon::Response.new + response.status = 200 + # just use the part number as the ETag, for simplicity + response.headers["ETag"] = part_number.to_s + response + end + end # Mock + end # Storage + end # Aws +end # Fog diff --git a/lib/fog/aws/requests/sts/assume_role.rb b/lib/fog/aws/requests/sts/assume_role.rb new file mode 100644 index 000000000..7a9bca4d4 --- /dev/null +++ b/lib/fog/aws/requests/sts/assume_role.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class STS + class Real + require 'fog/aws/parsers/sts/assume_role' + + # Assume Role + # + # ==== Parameters + # * role_session_name<~String> - An identifier for the assumed role. + # * role_arn<~String> - The ARN of the role the caller is assuming. + # * external_id<~String> - An optional unique identifier required by the assuming role's trust identity. + # * policy<~String> - An optional JSON policy document + # * duration<~Integer> - Duration (of seconds) for the assumed role credentials to be valid (default 3600) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Arn'<~String>: The ARN of the assumed role/user + # * 'AccessKeyId'<~String>: The Aws access key of the temporary credentials for the assumed role + # * 'SecretAccessKey'<~String>: The Aws secret key of the temporary credentials for the assumed role + # * 'SessionToken'<~String>: The Aws session token of the temporary credentials for the assumed role + # * 'Expiration'<~Time>: The expiration time of the temporary credentials for the assumed role + # + # ==== See Also + # http://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html + # + + def assume_role(role_session_name, role_arn, external_id=nil, policy=nil, duration=3600) + request({ + 'Action' => 'AssumeRole', + 'RoleSessionName' => role_session_name, + 'RoleArn' => role_arn, + 'Policy' => policy && Fog::JSON.encode(policy), + 'DurationSeconds' => duration, + 'ExternalId' => external_id, + :idempotent => true, + :parser => Fog::Parsers::AWS::STS::AssumeRole.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/sts/assume_role_with_saml.rb b/lib/fog/aws/requests/sts/assume_role_with_saml.rb new file mode 100644 index 000000000..daa9583c4 --- /dev/null +++ b/lib/fog/aws/requests/sts/assume_role_with_saml.rb @@ -0,0 +1,44 @@ +module Fog + module AWS + class STS + class Real + require 'fog/aws/parsers/sts/assume_role_with_saml' + + # Assume Role with SAML + # + # ==== Parameters + # * role_arn<~String> - The ARN of the role the caller is assuming. + # * principal_arn<~String> - The Amazon Resource Name (ARN) of the SAML provider in IAM that describes the IdP. + # * saml_assertion<~String> - The base-64 encoded SAML authentication response provided by the IdP. + # * policy<~String> - An optional JSON policy document + # * duration<~Integer> - Duration (of seconds) for the assumed role credentials to be valid (default 3600) + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Arn'<~String>: The ARN of the assumed role/user + # * 'AccessKeyId'<~String>: The Aws access key of the temporary credentials for the assumed role + # * 'SecretAccessKey'<~String>: The Aws secret key of the temporary credentials for the assumed role + # * 'SessionToken'<~String>: The Aws session token of the temporary credentials for the assumed role + # * 'Expiration'<~Time>: The expiration time of the temporary credentials for the assumed role + # + # ==== See Also + # http://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithSAML.html + # + + def assume_role_with_saml(role_arn, principal_arn, saml_assertion, policy=nil, duration=3600) + request_unsigned({ + 'Action' => 'AssumeRoleWithSAML', + 'RoleArn' => role_arn, + 'PrincipalArn' => principal_arn, + 'SAMLAssertion' => saml_assertion, + 'Policy' => policy && Fog::JSON.encode(policy), + 'DurationSeconds' => duration, + :idempotent => true, + :parser => Fog::Parsers::AWS::STS::AssumeRoleWithSAML.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/sts/get_federation_token.rb b/lib/fog/aws/requests/sts/get_federation_token.rb new file mode 100644 index 000000000..192e7ceb5 --- /dev/null +++ b/lib/fog/aws/requests/sts/get_federation_token.rb @@ -0,0 +1,62 @@ +module Fog + module AWS + class STS + class Real + require 'fog/aws/parsers/sts/get_session_token' + + # Get federation token + # + # ==== Parameters + # * name<~String>: The name of the federated user. + # Minimum length of 2. Maximum length of 32. + # * policy<~String>: Optional policy that specifies the permissions + # that are granted to the federated user + # Minimum length of 1. Maximum length of 2048. + # * duration<~Integer>: Optional duration, in seconds, that the session + # should last. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'SessionToken'<~String> - + # * 'SecretAccessKey'<~String> - + # * 'Expiration'<~String> - + # * 'AccessKeyId'<~String> - + # * 'Arn'<~String> - + # * 'FederatedUserId'<~String> - + # * 'PackedPolicySize'<~String> - + # * 'RequestId'<~String> - Id of the request + # + # ==== See Also + # http://docs.aws.amazon.com/STS/latest/APIReference/API_GetFederationToken.html + + def get_federation_token(name, policy, duration=43200) + request({ + 'Action' => 'GetFederationToken', + 'Name' => name, + 'Policy' => Fog::JSON.encode(policy), + 'DurationSeconds' => duration, + :idempotent => true, + :parser => Fog::Parsers::AWS::STS::GetSessionToken.new + }) + end + end + class Mock + def get_federation_token(name, policy, duration=43200) + Excon::Response.new.tap do |response| + response.status = 200 + response.body = { + 'SessionToken' => Fog::Mock.random_base64(580), + 'SecretAccessKey' => Fog::Mock.random_base64(40), + 'Expiration' => (DateTime.now + duration).strftime('%FT%TZ'), + 'AccessKeyId' => Fog::AWS::Mock.key_id(20), + 'Arn' => "arn:aws:sts::#{Fog::AWS::Mock.owner_id}:federated-user/#{name}", + 'FederatedUserId' => "#{Fog::AWS::Mock.owner_id}:#{name}", + 'PackedPolicySize' => Fog::Mock.random_numbers(2), + 'RequestId' => Fog::AWS::Mock.request_id + } + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/sts/get_session_token.rb b/lib/fog/aws/requests/sts/get_session_token.rb new file mode 100644 index 000000000..18d02f45f --- /dev/null +++ b/lib/fog/aws/requests/sts/get_session_token.rb @@ -0,0 +1,18 @@ +module Fog + module AWS + class STS + class Real + require 'fog/aws/parsers/sts/get_session_token' + + def get_session_token(duration=43200) + request({ + 'Action' => 'GetSessionToken', + 'DurationSeconds' => duration, + :idempotent => true, + :parser => Fog::Parsers::AWS::STS::GetSessionToken.new + }) + end + end + end + end +end diff --git a/lib/fog/aws/ses.rb b/lib/fog/aws/ses.rb new file mode 100644 index 000000000..3c8864d72 --- /dev/null +++ b/lib/fog/aws/ses.rb @@ -0,0 +1,141 @@ +require 'fog/aws/core' + +module Fog + module AWS + class SES < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class InvalidParameterError < Fog::Errors::Error; end + class MessageRejected < Fog::Errors::Error; end + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/ses' + request :delete_verified_email_address + request :verify_email_address + request :verify_domain_identity + request :get_send_quota + request :get_send_statistics + request :list_verified_email_addresses + request :send_email + request :send_raw_email + + class Mock + def initialize(options={}) + Fog::Mock.not_implemented + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to SES + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # ses = SES.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'us-east-1' and etc. + # + # ==== Returns + # * SES object with connection to Aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.ses' + @connection_options = options[:connection_options] || {} + options[:region] ||= 'us-east-1' + @host = options[:host] || "email.#{options[:region]}.amazonaws.com" + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @hmac = Fog::HMAC.new('sha256', @aws_secret_access_key) + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + headers = { + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Date' => Fog::Time.now.to_date_header, + } + headers['x-amz-security-token'] = @aws_session_token if @aws_session_token + #Aws3-HTTPS AwsAccessKeyId=, Algorithm=HmacSHA256, Signature= + headers['X-Amzn-Authorization'] = 'Aws3-HTTPS ' + headers['X-Amzn-Authorization'] << 'AwsAccessKeyId=' << @aws_access_key_id + headers['X-Amzn-Authorization'] << ', Algorithm=HmacSHA256' + headers['X-Amzn-Authorization'] << ', Signature=' << Base64.encode64(@hmac.sign(headers['Date'])).chomp! + + body = '' + for key in params.keys.sort + unless (value = params[key]).nil? + body << "#{key}=#{CGI.escape(value.to_s).gsub(/\+/, '%20')}&" + end + end + body.chop! # remove trailing '&' + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => headers, + :idempotent => idempotent, + :host => @host, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'MessageRejected' + Fog::AWS::SES::MessageRejected.slurp(error, match[:message]) + when 'InvalidParameterValue' + Fog::AWS::SES::InvalidParameterError.slurp(error, match[:message]) + else + Fog::AWS::SES::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/signaturev4.rb b/lib/fog/aws/signaturev4.rb new file mode 100644 index 000000000..3ae483d13 --- /dev/null +++ b/lib/fog/aws/signaturev4.rb @@ -0,0 +1,119 @@ +require 'fog/aws/core' + +# See http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html +module Fog + module AWS + class SignatureV4 + ALGORITHM = 'Aws4-HMAC-SHA256' + def initialize(aws_access_key_id, secret_key, region, service) + @region = region + @service = service + @aws_access_key_id = aws_access_key_id + @hmac = Fog::HMAC.new('sha256', 'Aws4' + secret_key) + end + + def signature_parameters(params, date, body_sha = nil) + params = params.dup.merge(:query => params[:query].merge( + 'X-Amz-Algorithm' => ALGORITHM, + 'X-Amz-Credential' => "#{@aws_access_key_id}/#{credential_scope(date)}", + 'X-Amz-SignedHeaders' => signed_headers(params[:headers]) + )) + signature_components(params, date, body_sha) + end + + def signature_header(params, date, body_sha = nil) + components_to_header(signature_components(params, date, body_sha)) + end + + def sign(params, date) #legacy method name + signature_header(params, date) + end + + def components_to_header components + "#{components['X-Amz-Algorithm']} Credential=#{components['X-Amz-Credential']}, SignedHeaders=#{components['X-Amz-SignedHeaders']}, Signature=#{components['X-Amz-Signature']}" + end + + def signature_components(params, date, body_sha) + canonical_request = <<-DATA +#{params[:method].to_s.upcase} +#{canonical_path(params[:path])} +#{canonical_query_string(params[:query])} +#{canonical_headers(params[:headers])} +#{signed_headers(params[:headers])} +#{body_sha || Digest::SHA256.hexdigest(params[:body] || '')} +DATA + canonical_request.chop! + + string_to_sign = <<-DATA +#{ALGORITHM} +#{date.to_iso8601_basic} +#{credential_scope(date)} +#{Digest::SHA256.hexdigest(canonical_request)} +DATA + + string_to_sign.chop! + + signature = derived_hmac(date).sign(string_to_sign) + + { + 'X-Amz-Algorithm' => ALGORITHM, + 'X-Amz-Credential' => "#{@aws_access_key_id}/#{credential_scope(date)}", + 'X-Amz-SignedHeaders' => signed_headers(params[:headers]), + 'X-Amz-Signature' => signature.unpack('H*').first + } + end + + def derived_hmac(date) + kDate = @hmac.sign(date.utc.strftime('%Y%m%d')) + kRegion = Fog::HMAC.new('sha256', kDate).sign(@region) + kService = Fog::HMAC.new('sha256', kRegion).sign(@service) + kSigning = Fog::HMAC.new('sha256', kService).sign('aws4_request') + Fog::HMAC.new('sha256', kSigning) + end + + + def credential_scope(date) + "#{date.utc.strftime('%Y%m%d')}/#{@region}/#{@service}/aws4_request" + end + + protected + + def canonical_path(path) + components = path.split(%r{/+}, -1) + path = components.inject([]) do |acc, component| + case component + when '.' #canonicalize by removing . + when '..' then acc.pop#canonicalize by reducing .. + else + acc << component + end + acc + end.join('/') + path.empty? ? '/' : path + end + + def canonical_query_string(query) + canonical_query_string = [] + for key in (query || {}).keys.sort_by {|k| k.to_s} + component = "#{Fog::AWS.escape(key.to_s)}=#{Fog::AWS.escape(query[key].to_s)}" + canonical_query_string << component + end + canonical_query_string.join("&") + end + + def canonical_headers(headers) + canonical_headers = '' + + for key in headers.keys.sort_by {|k| k.to_s} + canonical_headers << "#{key.to_s.downcase}:#{headers[key].to_s.strip}\n" + end + canonical_headers + end + + def signed_headers(headers) + headers.keys.map {|key| key.to_s}.sort.map {|key| key.downcase}.join(';') + end + + end + end +end diff --git a/lib/fog/aws/simpledb.rb b/lib/fog/aws/simpledb.rb new file mode 100644 index 000000000..fa13597dd --- /dev/null +++ b/lib/fog/aws/simpledb.rb @@ -0,0 +1,211 @@ +require 'fog/aws/core' + +module Fog + module AWS + class SimpleDB < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :nil_string, :path, :port, :scheme, :persistent, :region, :aws_session_token, :use_iam_profile, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/simpledb' + request :batch_put_attributes + request :create_domain + request :delete_attributes + request :delete_domain + request :domain_metadata + request :get_attributes + request :list_domains + request :put_attributes + request :select + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :domains => {} + } + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + end + + def data + self.class.data[@aws_access_key_id] + end + + def reset_data + self.class.data.delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to SimpleDB + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # sdb = SimpleDB.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * SimpleDB object with connection to aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @connection_options = options[:connection_options] || {} + @nil_string = options[:nil_string]|| 'nil' + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.simpledb' + + options[:region] ||= 'us-east-1' + @host = options[:host] || case options[:region] + when 'us-east-1' + 'sdb.amazonaws.com' + else + "sdb.#{options[:region]}.amazonaws.com" + end + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + private + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @hmac = Fog::HMAC.new('sha256', @aws_secret_access_key) + end + + def encode_attributes(attributes, replace_attributes = [], expected_attributes = {}) + encoded_attributes = {} + if attributes + + expected_attributes.keys.each_with_index do |exkey, index| + for value in Array(expected_attributes[exkey]) + encoded_attributes["Expected.#{index}.Name"] = exkey.to_s + encoded_attributes["Expected.#{index}.Value"] = sdb_encode(value) + end + end + + index = 0 + for key in attributes.keys + for value in Array(attributes[key]) + encoded_attributes["Attribute.#{index}.Name"] = key.to_s + if replace_attributes.include?(key) + encoded_attributes["Attribute.#{index}.Replace"] = 'true' + end + encoded_attributes["Attribute.#{index}.Value"] = sdb_encode(value) + index += 1 + end + end + end + encoded_attributes + end + + def encode_attribute_names(attributes) + Fog::AWS.indexed_param('AttributeName', attributes.map {|attribute| attributes.to_s}) + end + + def encode_batch_attributes(items, replace_attributes = Hash.new([])) + encoded_attributes = {} + if items + item_index = 0 + for item_key in items.keys + encoded_attributes["Item.#{item_index}.ItemName"] = item_key.to_s + attribute_index = 0 + for attribute_key in items[item_key].keys + for value in Array(items[item_key][attribute_key]) + encoded_attributes["Item.#{item_index}.Attribute.#{attribute_index}.Name"] = attribute_key.to_s + if replace_attributes[item_key].include?(attribute_key) + encoded_attributes["Item.#{item_index}.Attribute.#{attribute_index}.Replace"] = 'true' + end + encoded_attributes["Item.#{item_index}.Attribute.#{attribute_index}.Value"] = sdb_encode(value) + attribute_index += 1 + end + end + item_index += 1 + end + end + encoded_attributes + end + + def reload + @connection.reset + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body = Fog::AWS.signed_params( + params, + { + :aws_access_key_id => @aws_access_key_id, + :aws_session_token => @aws_session_token, + :hmac => @hmac, + :host => @host, + :path => @path, + :port => @port, + :version => '2009-04-15' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, idempotent, parser) + end + else + _request(body, idempotent, parser) + end + end + + def _request(body, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :headers => { 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8' }, + :idempotent => idempotent, + :method => 'POST', + :parser => parser + }) + end + + def sdb_encode(value) + if value.nil? + @nil_string + else + value.to_s + end + end + end + end + end +end diff --git a/lib/fog/aws/sns.rb b/lib/fog/aws/sns.rb new file mode 100644 index 000000000..faa830bae --- /dev/null +++ b/lib/fog/aws/sns.rb @@ -0,0 +1,160 @@ +require 'fog/aws/core' + +module Fog + module AWS + class SNS < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :host, :path, :port, :scheme, :persistent, :region, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/sns' + request :add_permission + request :confirm_subscription + request :create_topic + request :delete_topic + request :get_topic_attributes + request :list_subscriptions + request :list_subscriptions_by_topic + request :list_topics + request :publish + request :remove_permission + request :set_topic_attributes + request :subscribe + request :unsubscribe + + model_path 'fog/aws/models/sns' + model :topic + collection :topics + + class Mock + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :topics => {}, + :subscriptions => {}, + } + end + end + end + + attr_reader :region + + def initialize(options={}) + @region = options[:region] || 'us-east-1' + @aws_access_key_id = options[:aws_access_key_id] + @account_id = "12345678910" + @module = "sns" + + unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to SNS + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # sns = SNS.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * SNS object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @connection_options = options[:connection_options] || {} + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.sns' + + options[:region] ||= 'us-east-1' + @region = options[:region] + @host = options[:host] || "sns.#{options[:region]}.amazonaws.com" + + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + end + + attr_reader :region + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'sns') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Aws.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :method => 'POST', + :aws_session_token => @aws_session_token, + :signer => @signer, + :host => @host, + :path => @path, + :port => @port + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :idempotent => idempotent, + :headers => headers, + :method => 'POST', + :parser => parser + }) + end + end + end + end +end diff --git a/lib/fog/aws/sqs.rb b/lib/fog/aws/sqs.rb new file mode 100644 index 000000000..97c8a1370 --- /dev/null +++ b/lib/fog/aws/sqs.rb @@ -0,0 +1,164 @@ +require 'fog/aws/core' + +module Fog + module AWS + class SQS < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :region, :host, :path, :port, :scheme, :persistent, :aws_session_token, :use_iam_profile, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/sqs' + request :change_message_visibility + request :create_queue + request :delete_message + request :delete_queue + request :get_queue_attributes + request :list_queues + request :receive_message + request :send_message + request :set_queue_attributes + + class Mock + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :owner_id => Fog::AWS::Mock.owner_id, + :queues => {} + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @region = options[:region] || 'us-east-1' + + unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to SQS + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # sqs = SQS.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # * region<~String> - optional region to use. For instance, 'eu-west-1', 'us-east-1' and etc. + # + # ==== Returns + # * SQS object with connection to Aws. + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.sqs' + @connection_options = options[:connection_options] || {} + options[:region] ||= 'us-east-1' + @region = options[:region] + @host = options[:host] || "sqs.#{options[:region]}.amazonaws.com" + + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + + setup_credentials(options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'sqs') + end + + def path_from_queue_url(queue_url) + queue_url.split('.com', 2).last.sub(/^:[0-9]+/, '') + end + + def request(params) + refresh_credentials_if_expired + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + path = params.delete(:path) + + body, headers = Aws.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :method => 'POST', + :aws_session_token => @aws_session_token, + :signer => @signer, + :host => @host, + :path => path || @path, + :port => @port, + :version => '2009-02-01' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser, path) + end + else + _request(body, headers, idempotent, parser, path) + end + end + + def _request(body, headers, idempotent, parser, path) + args = { + :body => body, + :expects => 200, + :idempotent => idempotent, + :headers => headers, + :method => 'POST', + :parser => parser, + :path => path + }.reject{|_,v| v.nil? } + + @connection.request(args) + end + end + end + end +end diff --git a/lib/fog/aws/storage.rb b/lib/fog/aws/storage.rb new file mode 100644 index 000000000..7d8fd1e67 --- /dev/null +++ b/lib/fog/aws/storage.rb @@ -0,0 +1,687 @@ +require 'fog/aws/core' + +module Fog + module Storage + class Aws < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + COMPLIANT_BUCKET_NAMES = /^(?:[a-z]|\d(?!\d{0,2}(?:\.\d{1,3}){3}$))(?:[a-z0-9]|\.(?![\.\-])|\-(?![\.])){1,61}[a-z0-9]$/ + + DEFAULT_REGION = 'us-east-1' + + DEFAULT_SCHEME = 'https' + DEFAULT_SCHEME_PORT = { + 'http' => 80, + 'https' => 443 + } + + VALID_QUERY_KEYS = %w[ + acl + cors + delete + lifecycle + location + logging + notification + partNumber + policy + requestPayment + response-cache-control + response-content-disposition + response-content-encoding + response-content-language + response-content-type + response-expires + restore + tagging + torrent + uploadId + uploads + versionId + versioning + versions + website + ] + + requires :aws_access_key_id, :aws_secret_access_key + recognizes :endpoint, :region, :host, :port, :scheme, :persistent, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :path_style, :instrumentor, :instrumentor_name, :aws_signature_version + + secrets :aws_secret_access_key, :hmac + + model_path 'fog/aws/models/storage' + collection :directories + model :directory + collection :files + model :file + + request_path 'fog/aws/requests/storage' + request :abort_multipart_upload + request :complete_multipart_upload + request :copy_object + request :delete_bucket + request :delete_bucket_cors + request :delete_bucket_lifecycle + request :delete_bucket_policy + request :delete_bucket_website + request :delete_object + request :delete_multiple_objects + request :delete_bucket_tagging + request :get_bucket + request :get_bucket_acl + request :get_bucket_cors + request :get_bucket_lifecycle + request :get_bucket_location + request :get_bucket_logging + request :get_bucket_object_versions + request :get_bucket_policy + request :get_bucket_tagging + request :get_bucket_versioning + request :get_bucket_website + request :get_object + request :get_object_acl + request :get_object_torrent + request :get_object_http_url + request :get_object_https_url + request :get_object_url + request :get_request_payment + request :get_service + request :head_bucket + request :head_object + request :initiate_multipart_upload + request :list_multipart_uploads + request :list_parts + request :post_object_hidden_fields + request :post_object_restore + request :put_bucket + request :put_bucket_acl + request :put_bucket_cors + request :put_bucket_lifecycle + request :put_bucket_logging + request :put_bucket_policy + request :put_bucket_tagging + request :put_bucket_versioning + request :put_bucket_website + request :put_object + request :put_object_acl + request :put_object_url + request :put_request_payment + request :sync_clock + request :upload_part + + module Utils + attr_accessor :region + + def cdn + @cdn ||= Fog::AWS::CDN.new( + :aws_access_key_id => @aws_access_key_id, + :aws_secret_access_key => @aws_secret_access_key, + :use_iam_profile => @use_iam_profile + ) + end + + def http_url(params, expires) + signed_url(params.merge(:scheme => 'http'), expires) + end + + def https_url(params, expires) + signed_url(params.merge(:scheme => 'https'), expires) + end + + def url(params, expires) + Fog::Logger.deprecation("Fog::Storage::AWS => #url is deprecated, use #https_url instead [light_black](#{caller.first})[/]") + https_url(params, expires) + end + + def request_url(params) + params = request_params(params) + params_to_url(params) + end + + def signed_url(params, expires) + #convert expires from a point in time to a delta to now + now = Fog::Time.now + + expires = expires.to_i - now.to_i + params[:headers] ||= {} + + params[:query]||= {} + params[:query]['X-Amz-Expires'] = expires + params[:query]['X-Amz-Date'] = now.to_iso8601_basic + + if @aws_session_token + params[:query]['X-Amz-Security-Token'] = @aws_session_token + end + + params = request_params(params) + params[:headers][:host] = params[:host] + + signature = @signer.signature_parameters(params, now, "UNSIGNED-PAYLOAD") + + params[:query] = (params[:query] || {}).merge(signature) + + params_to_url(params) + end + + private + + def region_to_host(region=nil) + case region.to_s + when DEFAULT_REGION, '' + 's3.amazonaws.com' + else + "s3-#{region}.amazonaws.com" + end + end + + def object_to_path(object_name=nil) + '/' + escape(object_name.to_s).gsub('%2F','/') + end + + def bucket_to_path(bucket_name, path=nil) + "/#{escape(bucket_name.to_s)}#{path}" + end + + # NOTE: differs from Fog::AWS.escape by NOT escaping `/` + def escape(string) + string.gsub(/([^a-zA-Z0-9_.\-~\/]+)/) { + "%" + $1.unpack("H2" * $1.bytesize).join("%").upcase + } + end + + # Transforms things like bucket_name, object_name, region + # + # Should yield the same result when called f*f + def request_params(params) + headers = params[:headers] || {} + + if params[:scheme] + scheme = params[:scheme] + port = params[:port] || DEFAULT_SCHEME_PORT[scheme] + else + scheme = @scheme + port = @port + end + if DEFAULT_SCHEME_PORT[scheme] == port + port = nil + end + + if params[:region] + region = params[:region] + host = params[:host] || region_to_host(region) + else + region = @region || DEFAULT_REGION + host = params[:host] || @host || region_to_host(region) + end + + path = params[:path] || object_to_path(params[:object_name]) + path = '/' + path if path[0..0] != '/' + + if params[:bucket_name] + bucket_name = params[:bucket_name] + + path_style = params.fetch(:path_style, @path_style) + if !path_style + if COMPLIANT_BUCKET_NAMES !~ bucket_name + Fog::Logger.warning("fog: the specified s3 bucket name(#{bucket_name}) is not a valid dns name, which will negatively impact performance. For details see: http://docs.amazonwebservices.com/AmazonS3/latest/dev/BucketRestrictions.html") + path_style = true + elsif scheme == 'https' && bucket_name =~ /\./ + Fog::Logger.warning("fog: the specified s3 bucket name(#{bucket_name}) contains a '.' so is not accessible over https as a virtual hosted bucket, which will negatively impact performance. For details see: http://docs.amazonwebservices.com/AmazonS3/latest/dev/BucketRestrictions.html") + path_style = true + end + end + + if path_style + path = bucket_to_path bucket_name, path + else + host = [bucket_name, host].join('.') + end + end + + ret = params.merge({ + :scheme => scheme, + :host => host, + :port => port, + :path => path, + :headers => headers + }) + + # + ret.delete(:path_style) + ret.delete(:bucket_name) + ret.delete(:object_name) + ret.delete(:region) + + ret + end + + def params_to_url(params) + query = params[:query] && params[:query].map do |key, value| + if value + [key, escape(value.to_s)].join('=') + else + key + end + end.join('&') + + URI::Generic.build({ + :scheme => params[:scheme], + :host => params[:host], + :port => params[:port], + :path => params[:path], + :query => query, + }).to_s + end + end + + class Mock + include Utils + + def self.acls(type) + case type + when 'private' + { + "AccessControlList" => [ + { + "Permission" => "FULL_CONTROL", + "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + } + ], + "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + } + when 'public-read' + { + "AccessControlList" => [ + { + "Permission" => "FULL_CONTROL", + "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + }, + { + "Permission" => "READ", + "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AllUsers"} + } + ], + "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + } + when 'public-read-write' + { + "AccessControlList" => [ + { + "Permission" => "FULL_CONTROL", + "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + }, + { + "Permission" => "READ", + "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AllUsers"} + }, + { + "Permission" => "WRITE", + "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AllUsers"} + } + ], + "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + } + when 'authenticated-read' + { + "AccessControlList" => [ + { + "Permission" => "FULL_CONTROL", + "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + }, + { + "Permission" => "READ", + "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"} + } + ], + "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"} + } + end + end + + def self.data + @data ||= Hash.new do |hash, region| + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :acls => { + :bucket => {}, + :object => {} + }, + :buckets => {}, + :cors => { + :bucket => {} + }, + :bucket_tagging => {}, + :multipart_uploads => {} + } + end + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + if @endpoint = options[:endpoint] + endpoint = URI.parse(@endpoint) + @host = endpoint.host + @scheme = endpoint.scheme + @port = endpoint.port + else + @region = options[:region] || DEFAULT_REGION + @host = options[:host] || region_to_host(@region) + @scheme = options[:scheme] || DEFAULT_SCHEME + @port = options[:port] || DEFAULT_SCHEME_PORT[@scheme] + end + @path_style = options[:path_style] || false + setup_credentials(options) + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 's3') + end + end + + class Real + include Utils + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to S3 + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # s3 = Fog::Storage.new( + # :provider => "Aws", + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * S3 object with connection to aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.storage' + @connection_options = options[:connection_options] || {} + @persistent = options.fetch(:persistent, false) + @signature_version = options.fetch(:aws_signature_version, 4) + validate_signature_version! + @path_style = options[:path_style] || false + + if @endpoint = options[:endpoint] + endpoint = URI.parse(@endpoint) + @host = endpoint.host + @scheme = endpoint.scheme + @port = endpoint.port + else + @region = options[:region] || DEFAULT_REGION + @host = options[:host] || region_to_host(@region) + @scheme = options[:scheme] || DEFAULT_SCHEME + @port = options[:port] || DEFAULT_SCHEME_PORT[@scheme] + end + + setup_credentials(options) + end + + def reload + @connection.reset if @connection + end + + private + + def validate_signature_version! + unless @signature_version == 2 || @signature_version == 4 + raise "Unknown signature version #{@signature_version}; valid versions are 2 or 4" + end + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + if @signature_version == 4 + @signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 's3') + elsif @signature_version == 2 + @hmac = Fog::HMAC.new('sha1', @aws_secret_access_key) + end + end + + def connection(scheme, host, port) + uri = "#{scheme}://#{host}:#{port}" + if @persistent + unless uri == @connection_uri + @connection_uri = uri + reload + @connection = nil + end + else + @connection = nil + end + @connection ||= Fog::XML::Connection.new(uri, @persistent, @connection_options) + end + + def request(params, &block) + refresh_credentials_if_expired + + date = Fog::Time.now + + params = params.dup + params[:headers] = (params[:headers] || {}).dup + + params[:headers]['x-amz-security-token'] = @aws_session_token if @aws_session_token + + if @signature_version == 2 + expires = date.to_date_header + params[:headers]['Date'] = expires + params[:headers]['Authorization'] = "Aws #{@aws_access_key_id}:#{signature_v2(params, expires)}" + end + + params = request_params(params) + scheme = params.delete(:scheme) + host = params.delete(:host) + port = params.delete(:port) || DEFAULT_SCHEME_PORT[scheme] + params[:headers]['Host'] = host + + + if @signature_version == 4 + params[:headers]['x-amz-date'] = date.to_iso8601_basic + if params[:body].respond_to?(:read) + # See http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html + params[:headers]['x-amz-content-sha256'] = 'STREAMING-Aws4-HMAC-SHA256-PAYLOAD' + params[:headers]['x-amz-decoded-content-length'] = params[:headers].delete 'Content-Length' + + encoding = "aws-chunked" + + encoding += ", #{params[:headers]['Content-Encoding']}" if params[:headers]['Content-Encoding'] + params[:headers]['Content-Encoding'] = encoding + else + params[:headers]['x-amz-content-sha256'] ||= Digest::SHA256.hexdigest(params[:body] || '') + end + signature_components = @signer.signature_components(params, date, params[:headers]['x-amz-content-sha256']) + params[:headers]['Authorization'] = @signer.components_to_header(signature_components) + + if params[:body].respond_to?(:read) + body = params.delete :body + params[:request_block] = S3Streamer.new(body, signature_components['X-Amz-Signature'], @signer, date) + end + end + # FIXME: ToHashParser should make this not needed + original_params = params.dup + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(scheme, host, port, params, original_params, &block) + end + else + _request(scheme, host, port, params, original_params, &block) + end + end + + def _request(scheme, host, port, params, original_params, &block) + connection(scheme, host, port).request(params, &block) + rescue Excon::Errors::MovedPermanently, Excon::Errors::TemporaryRedirect => error + headers = (error.response.is_a?(Hash) ? error.response[:headers] : error.response.headers) + new_params = {} + if headers.has_key?('Location') + new_params[:host] = URI.parse(headers['Location']).host + else + body = error.response.is_a?(Hash) ? error.response[:body] : error.response.body + new_params[:bucket_name] = %r{([^<]*)}.match(body).captures.first + new_params[:host] = %r{([^<]*)}.match(body).captures.first + end + Fog::Logger.warning("fog: followed redirect to #{host}, connecting to the matching region will be more performant") + original_region, original_signer = @region, @signer + @region = case new_params[:host] + when 's3.amazonaws.com', 's3-external-1.amazonaws.com' + DEFAULT_REGION + else + %r{s3[\.\-]([^\.]*).amazonaws.com}.match(new_params[:host]).captures.first + end + if @signature_version == 4 + @signer = Fog::AWS::SignatureV4.new(@aws_access_key_id, @aws_secret_access_key, @region, 's3') + original_params[:headers].delete('Authorization') + end + response = request(original_params.merge(new_params), &block) + @region, @signer = original_region, original_signer + response + end + + # See http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html + + class S3Streamer + attr_accessor :body, :signature, :signer, :finished, :date, :initial_signature + def initialize(body, signature, signer, date) + self.body = body + self.date = date + self.signature = signature + self.initial_signature = signature + self.signer = signer + if body.respond_to?(:binmode) + body.binmode + end + + if body.respond_to?(:pos=) + body.pos = 0 + end + + end + + #called if excon wants to retry the request. As well as rewinding the body + #we must also reset the signature + def rewind + self.signature = initial_signature + body.rewind + end + + def call + if finished + '' + else + next_chunk + end + end + + def next_chunk + data = body.read(0x10000) + if data.nil? + self.finished = true + data = '' + end + self.signature = sign_chunk(data, signature) + "#{data.length.to_s(16)};chunk-signature=#{signature}\r\n#{data}\r\n" + end + + + def sign_chunk(data, previous_signature) + string_to_sign = <<-DATA +Aws4-HMAC-SHA256-PAYLOAD +#{date.to_iso8601_basic} +#{signer.credential_scope(date)} +#{previous_signature} +#{Digest::SHA256.hexdigest('')} +#{Digest::SHA256.hexdigest(data)} +DATA + hmac = signer.derived_hmac(date) + hmac.sign(string_to_sign.strip).unpack('H*').first + end + end + + def signature_v2(params, expires) + headers = params[:headers] || {} + + string_to_sign = +<<-DATA +#{params[:method].to_s.upcase} +#{headers['Content-MD5']} +#{headers['Content-Type']} +#{expires} +DATA + + amz_headers, canonical_amz_headers = {}, '' + for key, value in headers + if key[0..5] == 'x-amz-' + amz_headers[key] = value + end + end + amz_headers = amz_headers.sort {|x, y| x[0] <=> y[0]} + for key, value in amz_headers + canonical_amz_headers << "#{key}:#{value}\n" + end + string_to_sign << canonical_amz_headers + + query_string = '' + if params[:query] + query_args = [] + for key in params[:query].keys.sort + if VALID_QUERY_KEYS.include?(key) + value = params[:query][key] + if value + query_args << "#{key}=#{value}" + else + query_args << key + end + end + end + if query_args.any? + query_string = '?' + query_args.join('&') + end + end + + canonical_path = (params[:path] || object_to_path(params[:object_name])).to_s + canonical_path = '/' + canonical_path if canonical_path[0..0] != '/' + + if params[:bucket_name] + canonical_resource = "/#{params[:bucket_name]}#{canonical_path}" + else + canonical_resource = canonical_path + end + canonical_resource << query_string + string_to_sign << canonical_resource + signed_string = @hmac.sign(string_to_sign) + Base64.encode64(signed_string).chomp! + end + end + end + end +end diff --git a/lib/fog/aws/sts.rb b/lib/fog/aws/sts.rb new file mode 100644 index 000000000..c51cb9c08 --- /dev/null +++ b/lib/fog/aws/sts.rb @@ -0,0 +1,185 @@ +require 'fog/aws/core' + +module Fog + module AWS + class STS < Fog::Service + extend Fog::AWS::CredentialFetcher::ServiceMethods + + class EntityAlreadyExists < Fog::AWS::STS::Error; end + class ValidationError < Fog::AWS::STS::Error; end + class AwsAccessKeysMissing < Fog::AWS::STS::Error; end + + recognizes :aws_access_key_id, :aws_secret_access_key, :host, :path, :port, :scheme, :persistent, :aws_session_token, :use_iam_profile, :aws_credentials_expire_at, :instrumentor, :instrumentor_name + + request_path 'fog/aws/requests/sts' + request :get_federation_token + request :get_session_token + request :assume_role + request :assume_role_with_saml + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :owner_id => Fog::AWS::Mock.owner_id, + :server_certificates => {} + } + end + end + + def self.reset + @data = nil + end + + def self.server_certificate_id + Fog::Mock.random_hex(16) + end + + def initialize(options={}) + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + end + + def data + self.class.data[@aws_access_key_id] + end + + def reset_data + self.class.data.delete(@aws_access_key_id) + end + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + end + end + + class Real + include Fog::AWS::CredentialFetcher::ConnectionMethods + # Initialize connection to STS + # + # ==== Notes + # options parameter must include values for :aws_access_key_id and + # :aws_secret_access_key in order to create a connection + # + # ==== Examples + # iam = STS.new( + # :aws_access_key_id => your_aws_access_key_id, + # :aws_secret_access_key => your_aws_secret_access_key + # ) + # + # ==== Parameters + # * options<~Hash> - config arguments for connection. Defaults to {}. + # + # ==== Returns + # * STS object with connection to Aws. + def initialize(options={}) + + @use_iam_profile = options[:use_iam_profile] + setup_credentials(options) + @instrumentor = options[:instrumentor] + @instrumentor_name = options[:instrumentor_name] || 'fog.aws.sts' + @connection_options = options[:connection_options] || {} + + @host = options[:host] || 'sts.amazonaws.com' + @path = options[:path] || '/' + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options) + end + + def reload + @connection.reset + end + + private + + def setup_credentials(options) + @aws_access_key_id = options[:aws_access_key_id] + @aws_secret_access_key = options[:aws_secret_access_key] + @aws_session_token = options[:aws_session_token] + @aws_credentials_expire_at = options[:aws_credentials_expire_at] + + if (@aws_access_key_id && @aws_secret_access_key) + @signer = Fog::AWS::SignatureV4.new(@aws_access_key_id, @aws_secret_access_key, 'us-east-1', 'sts') + end + end + + def request(params) + if (@signer == nil) + raise AwsAccessKeysMissing.new("Can't make unsigned requests, need aws_access_key_id and aws_secret_access_key") + end + + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + body, headers = Fog::AWS.signed_params_v4( + params, + { 'Content-Type' => 'application/x-www-form-urlencoded' }, + { + :method => 'POST', + :aws_session_token => @aws_session_token, + :signer => @signer, + :host => @host, + :path => @path, + :port => @port, + :version => '2011-06-15' + } + ) + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def request_unsigned(params) + idempotent = params.delete(:idempotent) + parser = params.delete(:parser) + + params['Version'] = '2011-06-15' + + headers = { 'Content-Type' => 'application/x-www-form-urlencoded', 'Host' => @host } + body = '' + for key in params.keys.sort + unless (value = params[key]).nil? + body << "#{key}=#{Fog::AWS.escape(value.to_s)}&" + end + end + body.chop! + + if @instrumentor + @instrumentor.instrument("#{@instrumentor_name}.request", params) do + _request(body, headers, idempotent, parser) + end + else + _request(body, headers, idempotent, parser) + end + end + + def _request(body, headers, idempotent, parser) + @connection.request({ + :body => body, + :expects => 200, + :idempotent => idempotent, + :headers => headers, + :method => 'POST', + :parser => parser + }) + rescue Excon::Errors::HTTPStatusError => error + match = Fog::AWS::Errors.match_error(error) + raise if match.empty? + raise case match[:code] + when 'EntityAlreadyExists', 'KeyPairMismatch', 'LimitExceeded', 'MalformedCertificate', 'ValidationError' + Fog::AWS::STS.const_get(match[:code]).slurp(error, match[:message]) + else + Fog::AWS::STS::Error.slurp(error, "#{match[:code]} => #{match[:message]}") + end + end + end + end + end +end diff --git a/lib/fog/aws/version.rb b/lib/fog/aws/version.rb index 0615e094f..62f3a43d8 100644 --- a/lib/fog/aws/version.rb +++ b/lib/fog/aws/version.rb @@ -1,5 +1,5 @@ module Fog - module Aws + module AWS VERSION = "0.0.1" end end diff --git a/tests/credentials_tests.rb b/tests/credentials_tests.rb new file mode 100644 index 000000000..d6d7ea442 --- /dev/null +++ b/tests/credentials_tests.rb @@ -0,0 +1,55 @@ +Shindo.tests('Aws | credentials', ['aws']) do + old_mock_value = Excon.defaults[:mock] + Excon.stubs.clear + + begin + Excon.defaults[:mock] = true + default_credentials = Fog::Compute::AWS.fetch_credentials({}) + Excon.stub({:method => :get, :path => "/latest/meta-data/iam/security-credentials/"}, {:status => 200, :body => 'arole'}) + + expires_at = Time.at(Time.now.to_i + 500) + credentials = { + 'AccessKeyId' => 'dummykey', + 'SecretAccessKey' => 'dummysecret', + 'Token' => 'dummytoken', + 'Expiration' => expires_at.xmlschema + } + + Excon.stub({:method => :get, :path => "/latest/meta-data/iam/security-credentials/arole"}, {:status => 200, :body => Fog::JSON.encode(credentials)}) + + tests("#fetch_credentials") do + returns({:aws_access_key_id => 'dummykey', + :aws_secret_access_key => 'dummysecret', + :aws_session_token => 'dummytoken', + :aws_credentials_expire_at => expires_at}) { Fog::Compute::AWS.fetch_credentials(:use_iam_profile => true) } + end + + compute = Fog::Compute::AWS.new(:use_iam_profile => true) + + tests("#refresh_credentials_if_expired") do + returns(nil){compute.refresh_credentials_if_expired} + end + + credentials['AccessKeyId'] = 'newkey' + credentials['SecretAccessKey'] = 'newsecret' + credentials['Expiration'] = (expires_at + 10).xmlschema + + Excon.stub({:method => :get, :path => "/latest/meta-data/iam/security-credentials/arole"}, {:status => 200, :body => Fog::JSON.encode(credentials)}) + + Fog::Time.now = expires_at + 1 + tests("#refresh_credentials_if_expired") do + returns(true){compute.refresh_credentials_if_expired} + returns("newkey"){ compute.instance_variable_get(:@aws_access_key_id)} + end + Fog::Time.now = Time.now + + tests("#fetch_credentials when the url 404s") do + Excon.stub({:method => :get, :path => "/latest/meta-data/iam/security-credentials/"}, {:status => 404, :body => 'not bound'}) + returns(default_credentials) {Fog::Compute::AWS.fetch_credentials(:use_iam_profile => true)} + end + + ensure + Excon.stubs.clear + Excon.defaults[:mock] = old_mock_value + end +end diff --git a/tests/helper.rb b/tests/helper.rb new file mode 100644 index 000000000..cb2589214 --- /dev/null +++ b/tests/helper.rb @@ -0,0 +1,21 @@ +require File.expand_path('../../lib/fog/aws', __FILE__) + +Bundler.require(:test) + +Excon.defaults.merge!(:debug_request => true, :debug_response => true) + +require File.expand_path(File.join(File.dirname(__FILE__), 'helpers', 'mock_helper')) + +# This overrides the default 600 seconds timeout during live test runs +if Fog.mocking? + Fog.timeout = ENV['FOG_TEST_TIMEOUT'] || 2000 + Fog::Logger.warning "Setting default fog timeout to #{Fog.timeout} seconds" +end + +def lorem_file + File.open(File.dirname(__FILE__) + '/lorem.txt', 'r') +end + +def array_differences(array_a, array_b) + (array_a - array_b) | (array_b - array_a) +end diff --git a/tests/helpers/collection_helper.rb b/tests/helpers/collection_helper.rb new file mode 100644 index 000000000..e73e7833d --- /dev/null +++ b/tests/helpers/collection_helper.rb @@ -0,0 +1,97 @@ +def collection_tests(collection, params = {}, mocks_implemented = true) + tests('success') do + + tests("#new(#{params.inspect})").succeeds do + pending if Fog.mocking? && !mocks_implemented + collection.new(params) + end + + tests("#create(#{params.inspect})").succeeds do + pending if Fog.mocking? && !mocks_implemented + @instance = collection.create(params) + end + # FIXME: work around for timing issue on AWS describe_instances mocks + + if Fog.mocking? && @instance.respond_to?(:ready?) + @instance.wait_for { ready? } + end + + tests("#all").succeeds do + pending if Fog.mocking? && !mocks_implemented + collection.all + end + + if !Fog.mocking? || mocks_implemented + @identity = @instance.identity + end + + tests("#get(#{@identity})").succeeds do + pending if Fog.mocking? && !mocks_implemented + collection.get(@identity) + end + + tests('Enumerable') do + pending if Fog.mocking? && !mocks_implemented + + methods = [ + 'all?', 'any?', 'find', 'detect', 'collect', 'map', + 'find_index', 'flat_map', 'collect_concat', 'group_by', + 'none?', 'one?' + ] + + # JRuby 1.7.5+ issue causes a SystemStackError: stack level too deep + # https://github.com/jruby/jruby/issues/1265 + if RUBY_PLATFORM == "java" and JRUBY_VERSION =~ /1\.7\.[5-8]/ + methods.delete('all?') + end + + methods.each do |enum_method| + if collection.respond_to?(enum_method) + tests("##{enum_method}").succeeds do + block_called = false + collection.send(enum_method) {|x| block_called = true } + block_called + end + end + end + + [ + 'max_by','min_by' + ].each do |enum_method| + if collection.respond_to?(enum_method) + tests("##{enum_method}").succeeds do + block_called = false + collection.send(enum_method) {|x| block_called = true; 0 } + block_called + end + end + + end + + end + + if block_given? + yield(@instance) + end + + if !Fog.mocking? || mocks_implemented + @instance.destroy + end + end + + tests('failure') do + + if !Fog.mocking? || mocks_implemented + @identity = @identity.to_s + @identity = @identity.gsub(/[a-zA-Z]/) { Fog::Mock.random_letters(1) } + @identity = @identity.gsub(/\d/) { Fog::Mock.random_numbers(1) } + @identity + end + + tests("#get('#{@identity}')").returns(nil) do + pending if Fog.mocking? && !mocks_implemented + collection.get(@identity) + end + + end +end diff --git a/tests/helpers/compute/flavors_helper.rb b/tests/helpers/compute/flavors_helper.rb new file mode 100644 index 000000000..b9170e816 --- /dev/null +++ b/tests/helpers/compute/flavors_helper.rb @@ -0,0 +1,32 @@ +def flavors_tests(connection, params = {}, mocks_implemented = true) + tests('success') do + + tests("#all").succeeds do + pending if Fog.mocking? && !mocks_implemented + connection.flavors.all + end + + if !Fog.mocking? || mocks_implemented + @identity = connection.flavors.first.identity + end + + tests("#get('#{@identity}')").succeeds do + pending if Fog.mocking? && !mocks_implemented + connection.flavors.get(@identity) + end + + end + + tests('failure') do + + if !Fog.mocking? || mocks_implemented + invalid_flavor_identity = connection.flavors.first.identity.to_s.gsub(/\w/, '0') + end + + tests("#get('#{invalid_flavor_identity}')").returns(nil) do + pending if Fog.mocking? && !mocks_implemented + connection.flavors.get(invalid_flavor_identity) + end + + end +end diff --git a/tests/helpers/compute/server_helper.rb b/tests/helpers/compute/server_helper.rb new file mode 100644 index 000000000..90a79fb12 --- /dev/null +++ b/tests/helpers/compute/server_helper.rb @@ -0,0 +1,25 @@ +def server_tests(connection, params = {}, mocks_implemented = true) + model_tests(connection.servers, params, mocks_implemented) do + + tests('#reload').returns(true) do + pending if Fog.mocking? && !mocks_implemented + @instance.wait_for { ready? } + identity = @instance.identity + !identity.nil? && identity == @instance.reload.identity + end + + responds_to([:ready?, :state]) + yield if block_given? + + tests('#reboot').succeeds do + pending if Fog.mocking? && !mocks_implemented + @instance.wait_for { ready? } + @instance.reboot + end + + if !Fog.mocking? || mocks_implemented + @instance.wait_for { ready? } + end + + end +end diff --git a/tests/helpers/compute/servers_helper.rb b/tests/helpers/compute/servers_helper.rb new file mode 100644 index 000000000..60a292211 --- /dev/null +++ b/tests/helpers/compute/servers_helper.rb @@ -0,0 +1,10 @@ +def servers_tests(connection, params = {}, mocks_implemented = true) + collection_tests(connection.servers, params, mocks_implemented) do + + if !Fog.mocking? || mocks_implemented + @instance.wait_for { ready? } + yield if block_given? + end + + end +end diff --git a/tests/helpers/dns_helper.rb b/tests/helpers/dns_helper.rb new file mode 100644 index 000000000..1c85cefe8 --- /dev/null +++ b/tests/helpers/dns_helper.rb @@ -0,0 +1,55 @@ +def dns_providers + { + :aws => { + :mocked => false + }, + :bluebox => { + :mocked => false, + :zone_attributes => { + :ttl => 60 + } + }, + :dnsimple => { + :mocked => false + }, + :dnsmadeeasy => { + :mocked => false + }, + :dynect => { + :mocked => false, + :zone_attributes => { + :email => 'fog@example.com' + } + }, + :linode => { + :mocked => false, + :zone_attributes => { + :email => 'fog@example.com' + } + }, + :zerigo => { + :mocked => false + }, + :rackspace => { + :mocked => false, + :zone_attributes => { + :email => 'fog@example.com' + } + }, + :rage4 => { + :mocked => false + } + } +end + +def generate_unique_domain( with_trailing_dot = false) + #get time (with 1/100th of sec accuracy) + #want unique domain name and if provider is fast, this can be called more than once per second + time= (Time.now.to_f * 100).to_i + domain = 'test-' + time.to_s + '.com' + if with_trailing_dot + domain+= '.' + end + + domain +end diff --git a/tests/helpers/formats_helper.rb b/tests/helpers/formats_helper.rb new file mode 100644 index 000000000..0053bb546 --- /dev/null +++ b/tests/helpers/formats_helper.rb @@ -0,0 +1,98 @@ +require "fog/schema/data_validator" + +# format related hackery +# allows both true.is_a?(Fog::Boolean) and false.is_a?(Fog::Boolean) +# allows both nil.is_a?(Fog::Nullable::String) and ''.is_a?(Fog::Nullable::String) +module Fog + module Boolean; end + module Nullable + module Boolean; end + module Integer; end + module String; end + module Time; end + module Float; end + module Hash; end + module Array; end + end +end +[FalseClass, TrueClass].each {|klass| klass.send(:include, Fog::Boolean)} +[FalseClass, TrueClass, NilClass, Fog::Boolean].each {|klass| klass.send(:include, Fog::Nullable::Boolean)} +[NilClass, String].each {|klass| klass.send(:include, Fog::Nullable::String)} +[NilClass, Time].each {|klass| klass.send(:include, Fog::Nullable::Time)} +[Integer, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Integer)} +[Float, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Float)} +[Hash, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Hash)} +[Array, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Array)} + +module Shindo + class Tests + # Generates a Shindo test that compares a hash schema to the result + # of the passed in block returning true if they match. + # + # The schema that is passed in is a Hash or Array of hashes that + # have Classes in place of values. When checking the schema the + # value should match the Class. + # + # Strict mode will fail if the data has additional keys. Setting + # +strict+ to +false+ will allow additional keys to appear. + # + # @param [Hash] schema A Hash schema + # @param [Hash] options Options to change validation rules + # @option options [Boolean] :allow_extra_keys + # If +true+ does not fail when keys are in the data that are + # not specified in the schema. This allows new values to + # appear in API output without breaking the check. + # @option options [Boolean] :allow_optional_rules + # If +true+ does not fail if extra keys are in the schema + # that do not match the data. Not recommended! + # @yield Data to check with schema + # + # @example Using in a test + # Shindo.tests("comparing welcome data against schema") do + # data = {:welcome => "Hello" } + # data_matches_schema(:welcome => String) { data } + # end + # + # comparing welcome data against schema + # + data matches schema + # + # @example Example schema + # { + # "id" => String, + # "ram" => Integer, + # "disks" => [ + # { + # "size" => Float + # } + # ], + # "dns_name" => Fog::Nullable::String, + # "active" => Fog::Boolean, + # "created" => DateTime + # } + # + # @return [Boolean] + def data_matches_schema(schema, options = {}) + test('data matches schema') do + validator = Fog::Schema::DataValidator.new + valid = validator.validate(yield, schema, options) + @message = validator.message unless valid + valid + end + end + + # @deprecated #formats is deprecated. Use #data_matches_schema instead + def formats(format, strict = true) + test('has proper format') do + if strict + options = {:allow_extra_keys => false, :allow_optional_rules => true} + else + options = {:allow_extra_keys => true, :allow_optional_rules => true} + end + validator = Fog::Schema::DataValidator.new + valid = validator.validate(yield, format, options) + @message = validator.message unless valid + valid + end + end + end +end diff --git a/tests/helpers/formats_helper_tests.rb b/tests/helpers/formats_helper_tests.rb new file mode 100644 index 000000000..dba2386f0 --- /dev/null +++ b/tests/helpers/formats_helper_tests.rb @@ -0,0 +1,110 @@ +Shindo.tests('test_helper', 'meta') do + + tests('comparing welcome data against schema') do + data = {:welcome => "Hello" } + data_matches_schema(:welcome => String) { data } + end + + tests('#data_matches_schema') do + tests('when value matches schema expectation') do + data_matches_schema({"key" => String}) { {"key" => "Value"} } + end + + tests('when values within an array all match schema expectation') do + data_matches_schema({"key" => [Integer]}) { {"key" => [1, 2]} } + end + + tests('when nested values match schema expectation') do + data_matches_schema({"key" => {:nested_key => String}}) { {"key" => {:nested_key => "Value"}} } + end + + tests('when collection of values all match schema expectation') do + data_matches_schema([{"key" => String}]) { [{"key" => "Value"}, {"key" => "Value"}] } + end + + tests('when collection is empty although schema covers optional members') do + data_matches_schema([{"key" => String}], {:allow_optional_rules => true}) { [] } + end + + tests('when additional keys are passed and not strict') do + data_matches_schema({"key" => String}, {:allow_extra_keys => true}) { {"key" => "Value", :extra => "Bonus"} } + end + + tests('when value is nil and schema expects NilClass') do + data_matches_schema({"key" => NilClass}) { {"key" => nil} } + end + + tests('when value and schema match as hashes') do + data_matches_schema({}) { {} } + end + + tests('when value and schema match as arrays') do + data_matches_schema([]) { [] } + end + + tests('when value is a Time') do + data_matches_schema({"time" => Time}) { {"time" => Time.now} } + end + + tests('when key is missing but value should be NilClass (#1477)') do + data_matches_schema({"key" => NilClass}, {:allow_optional_rules => true}) { {} } + end + + tests('when key is missing but value is nullable (#1477)') do + data_matches_schema({"key" => Fog::Nullable::String}, {:allow_optional_rules => true}) { {} } + end + end + + tests('#formats backwards compatible changes') do + + tests('when value matches schema expectation') do + formats({"key" => String}) { {"key" => "Value"} } + end + + tests('when values within an array all match schema expectation') do + formats({"key" => [Integer]}) { {"key" => [1, 2]} } + end + + tests('when nested values match schema expectation') do + formats({"key" => {:nested_key => String}}) { {"key" => {:nested_key => "Value"}} } + end + + tests('when collection of values all match schema expectation') do + formats([{"key" => String}]) { [{"key" => "Value"}, {"key" => "Value"}] } + end + + tests('when collection is empty although schema covers optional members') do + formats([{"key" => String}]) { [] } + end + + tests('when additional keys are passed and not strict') do + formats({"key" => String}, false) { {"key" => "Value", :extra => "Bonus"} } + end + + tests('when value is nil and schema expects NilClass') do + formats({"key" => NilClass}) { {"key" => nil} } + end + + tests('when value and schema match as hashes') do + formats({}) { {} } + end + + tests('when value and schema match as arrays') do + formats([]) { [] } + end + + tests('when value is a Time') do + formats({"time" => Time}) { {"time" => Time.now} } + end + + tests('when key is missing but value should be NilClass (#1477)') do + formats({"key" => NilClass}) { {} } + end + + tests('when key is missing but value is nullable (#1477)') do + formats({"key" => Fog::Nullable::String}) { {} } + end + + end + +end diff --git a/tests/helpers/mock_helper.rb b/tests/helpers/mock_helper.rb new file mode 100644 index 000000000..c3de9f28f --- /dev/null +++ b/tests/helpers/mock_helper.rb @@ -0,0 +1,110 @@ +# Use so you can run in mock mode from the command line +# +# FOG_MOCK=true fog + +if ENV["FOG_MOCK"] == "true" + Fog.mock! +end + +# if in mocked mode, fill in some fake credentials for us +if Fog.mock? + Fog.credentials = { + :aws_access_key_id => 'aws_access_key_id', + :aws_secret_access_key => 'aws_secret_access_key', + :ia_access_key_id => 'aws_access_key_id', + :ia_secret_access_key => 'aws_secret_access_key', + :bluebox_api_key => 'bluebox_api_key', + :bluebox_customer_id => 'bluebox_customer_id', + :brightbox_client_id => 'brightbox_client_id', + :brightbox_secret => 'brightbox_secret', + :cloudstack_disk_offering_id => '', + :cloudstack_host => 'http://cloudstack.example.org', + :cloudstack_network_ids => '', + :cloudstack_service_offering_id => '4437ac6c-9fe3-477a-57ec-60a5a45896a4', + :cloudstack_template_id => '8a31cf9c-f248-0588-256e-9dbf58785216', + :cloudstack_zone_id => 'c554c592-e09c-9df5-7688-4a32754a4305', + :cloudstack_project_id => 'f1f1f1f1-f1f1-f1f1-f1f1-f1f1f1f1f1f1', + :clodo_api_key => 'clodo_api_key', + :clodo_username => 'clodo_username', + :digitalocean_api_key => 'digitalocean_api_key', + :digitalocean_client_id => 'digitalocean_client_id', + :dnsimple_email => 'dnsimple_email', + :dnsimple_password => 'dnsimple_password', + :dnsmadeeasy_api_key => 'dnsmadeeasy_api_key', + :dnsmadeeasy_secret_key => 'dnsmadeeasy_secret_key', + :glesys_username => 'glesys_username', + :glesys_api_key => 'glesys_api_key', + :go_grid_api_key => 'go_grid_api_key', + :go_grid_shared_secret => 'go_grid_shared_secret', + :google_storage_access_key_id => 'google_storage_access_key_id', + :google_storage_secret_access_key => 'google_storage_secret_access_key', + :google_project => 'google_project_name', + :google_client_email => 'fake@developer.gserviceaccount.com', + :google_key_location => '~/fake.p12', + :hp_access_key => 'hp_access_key', + :hp_secret_key => 'hp_secret_key', + :hp_tenant_id => 'hp_tenant_id', + :hp_avl_zone => 'hp_avl_zone', + :os_account_meta_temp_url_key => 'os_account_meta_temp_url_key', + :ibm_username => 'ibm_username', + :ibm_password => 'ibm_password', + :joyent_username => "joyentuser", + :joyent_password => "joyentpass", + :linode_api_key => 'linode_api_key', + :local_root => '~/.fog', + :bare_metal_cloud_password => 'bare_metal_cloud_password', + :bare_metal_cloud_username => 'bare_metal_cloud_username', + :ninefold_compute_key => 'ninefold_compute_key', + :ninefold_compute_secret => 'ninefold_compute_secret', + :ninefold_storage_secret => 'ninefold_storage_secret', + :ninefold_storage_token => 'ninefold_storage_token', +# :public_key_path => '~/.ssh/id_rsa.pub', +# :private_key_path => '~/.ssh/id_rsa', + :opennebula_endpoint => 'http://opennebula:2633/RPC2', + :opennebula_username => 'oneadmin', + :opennebula_password => 'oneadmin', + :openstack_api_key => 'openstack_api_key', + :openstack_username => 'openstack_username', + :openstack_tenant => 'openstack_tenant', + :openstack_auth_url => 'http://openstack:35357/v2.0/tokens', + :ovirt_url => 'http://ovirt:8080/api', + :ovirt_username => 'admin@internal', + :ovirt_password => '123123', + :profitbricks_username => 'profitbricks_username', + :profitbricks_password => 'profitbricks_password', + :libvirt_uri => 'qemu://libvirt/system', + :rackspace_api_key => 'rackspace_api_key', + :rackspace_region => 'dfw', + :rackspace_username => 'rackspace_username', + :riakcs_access_key_id => 'riakcs_access_key_id', + :riakcs_secret_access_key => 'riakcs_secret_access_key', + :sakuracloud_api_token => 'sakuracloud_api_token', + :sakuracloud_api_token_secret => 'sakuracloud_api_token_secret', + :storm_on_demand_username => 'storm_on_demand_username', + :storm_on_demand_password => 'storm_on_demand_password', + :vcloud_host => 'vcloud_host', + :vcloud_password => 'vcloud_password', + :vcloud_username => 'vcloud_username', + :vcloud_director_host => 'vcloud-director-host', + :vcloud_director_password => 'vcloud_director_password', + :vcloud_director_username => 'vcd_user@vcd_org_name', + :zerigo_email => 'zerigo_email', + :zerigo_token => 'zerigo_token', + :dynect_customer => 'dynect_customer', + :dynect_username => 'dynect_username', + :dynect_password => 'dynect_password', + :vsphere_server => 'virtualcenter.lan', + :vsphere_username => 'apiuser', + :vsphere_password => 'apipassword', + :vsphere_expected_pubkey_hash => 'abcdef1234567890', + :libvirt_uri => 'qemu:///system', + :libvirt_username => 'root', + :libvirt_password => 'password', + :cloudsigma_username => 'csuname', + :cloudsigma_password => 'cspass', + :docker_username => 'docker-fan', + :docker_password => 'i<3docker', + :docker_email => 'dockerfan@gmail.com', + :docker_url => 'unix://var/run/docker.sock' + }.merge(Fog.credentials) +end diff --git a/tests/helpers/model_helper.rb b/tests/helpers/model_helper.rb new file mode 100644 index 000000000..e026a7b32 --- /dev/null +++ b/tests/helpers/model_helper.rb @@ -0,0 +1,31 @@ +def model_tests(collection, params = {}, mocks_implemented = true) + tests('success') do + + @instance = collection.new(params) + + tests("#save").succeeds do + pending if Fog.mocking? && !mocks_implemented + @instance.save + end + + if block_given? + yield(@instance) + end + + tests("#destroy").succeeds do + pending if Fog.mocking? && !mocks_implemented + @instance.destroy + end + + end +end + +# Generates a unique identifier with a random differentiator. +# Useful when rapidly re-running tests, so we don't have to wait +# serveral minutes for deleted objects to disappear from the API +# E.g. 'fog-test-1234' +def uniq_id(base_name = 'fog-test') + # random_differentiator + suffix = rand(65536).to_s(16).rjust(4, '0') + [base_name, suffix] * '-' +end diff --git a/tests/helpers/responds_to_helper.rb b/tests/helpers/responds_to_helper.rb new file mode 100644 index 000000000..598270095 --- /dev/null +++ b/tests/helpers/responds_to_helper.rb @@ -0,0 +1,11 @@ +module Shindo + class Tests + def responds_to(method_names) + for method_name in [*method_names] + tests("#respond_to?(:#{method_name})").returns(true) do + @instance.respond_to?(method_name) + end + end + end + end +end diff --git a/tests/helpers/schema_validator_tests.rb b/tests/helpers/schema_validator_tests.rb new file mode 100644 index 000000000..8715af391 --- /dev/null +++ b/tests/helpers/schema_validator_tests.rb @@ -0,0 +1,107 @@ +Shindo.tests('Fog::Schema::DataValidator', 'meta') do + + validator = Fog::Schema::DataValidator.new + + tests('#validate') do + + tests('returns true') do + + returns(true, 'when value matches schema expectation') do + validator.validate({"key" => "Value"}, {"key" => String}) + end + + returns(true, 'when values within an array all match schema expectation') do + validator.validate({"key" => [1, 2]}, {"key" => [Integer]}) + end + + returns(true, 'when nested values match schema expectation') do + validator.validate({"key" => {:nested_key => "Value"}}, {"key" => {:nested_key => String}}) + end + + returns(true, 'when collection of values all match schema expectation') do + validator.validate([{"key" => "Value"}, {"key" => "Value"}], [{"key" => String}]) + end + + returns(true, 'when collection is empty although schema covers optional members') do + validator.validate([], [{"key" => String}]) + end + + returns(true, 'when additional keys are passed and not strict') do + validator.validate({"key" => "Value", :extra => "Bonus"}, {"key" => String}, {:allow_extra_keys => true}) + end + + returns(true, 'when value is nil and schema expects NilClass') do + validator.validate({"key" => nil}, {"key" => NilClass}) + end + + returns(true, 'when value and schema match as hashes') do + validator.validate({}, {}) + end + + returns(true, 'when value and schema match as arrays') do + validator.validate([], []) + end + + returns(true, 'when value is a Time') do + validator.validate({"time" => Time.now}, {"time" => Time}) + end + + returns(true, 'when key is missing but value should be NilClass (#1477)') do + validator.validate({}, {"key" => NilClass}, {:allow_optional_rules => true}) + end + + returns(true, 'when key is missing but value is nullable (#1477)') do + validator.validate({}, {"key" => Fog::Nullable::String}, {:allow_optional_rules => true}) + end + + end + + tests('returns false') do + + returns(false, 'when value does not match schema expectation') do + validator.validate({"key" => nil}, {"key" => String}) + end + + returns(false, 'when key formats do not match') do + validator.validate({"key" => "Value"}, {:key => String}) + end + + returns(false, 'when additional keys are passed and strict') do + validator.validate({"key" => "Missing"}, {}) + end + + returns(false, 'when some keys do not appear') do + validator.validate({}, {"key" => String}) + end + + returns(false, 'when collection contains a member that does not match schema') do + validator.validate([{"key" => "Value"}, {"key" => 5}], [{"key" => String}]) + end + + returns(false, 'when collection has multiple schema patterns') do + validator.validate([{"key" => "Value"}], [{"key" => Integer}, {"key" => String}]) + end + + returns(false, 'when hash and array are compared') do + validator.validate({}, []) + end + + returns(false, 'when array and hash are compared') do + validator.validate([], {}) + end + + returns(false, 'when a hash is expected but another data type is found') do + validator.validate({"key" => {:nested_key => []}}, {"key" => {:nested_key => {}}}) + end + + returns(false, 'when key is missing but value should be NilClass (#1477)') do + validator.validate({}, {"key" => NilClass}, {:allow_optional_rules => false}) + end + + returns(false, 'when key is missing but value is nullable (#1477)') do + validator.validate({}, {"key" => Fog::Nullable::String}, {:allow_optional_rules => false}) + end + + end + end +end diff --git a/tests/helpers/succeeds_helper.rb b/tests/helpers/succeeds_helper.rb new file mode 100644 index 000000000..b54589e3a --- /dev/null +++ b/tests/helpers/succeeds_helper.rb @@ -0,0 +1,9 @@ +module Shindo + class Tests + def succeeds + test('succeeds') do + !!instance_eval(&Proc.new) + end + end + end +end diff --git a/tests/models/auto_scaling/activities_tests.rb b/tests/models/auto_scaling/activities_tests.rb new file mode 100644 index 000000000..a4b67831a --- /dev/null +++ b/tests/models/auto_scaling/activities_tests.rb @@ -0,0 +1,6 @@ +Shindo.tests('Aws::AutoScaling | activities', ['aws', 'auto_scaling_m']) do + + pending # FIXME: activity#save is not implemented + collection_tests(Fog::AWS[:auto_scaling].activities, {}, false) + +end diff --git a/tests/models/auto_scaling/configuration_test.rb b/tests/models/auto_scaling/configuration_test.rb new file mode 100644 index 000000000..3e0fbc6c4 --- /dev/null +++ b/tests/models/auto_scaling/configuration_test.rb @@ -0,0 +1,13 @@ +Shindo.tests('Aws::AutoScaling | configuration', ['aws', 'auto_scaling_m']) do + + params = { + :id => uniq_id, + :image_id => 'ami-8c1fece5', + :instance_type => 't1.micro' + } + + model_tests(Fog::AWS[:auto_scaling].configurations, params, false) do + @instance.wait_for { ready? } + end + +end diff --git a/tests/models/auto_scaling/configurations_tests.rb b/tests/models/auto_scaling/configurations_tests.rb new file mode 100644 index 000000000..476615986 --- /dev/null +++ b/tests/models/auto_scaling/configurations_tests.rb @@ -0,0 +1,11 @@ +Shindo.tests('Aws::AutoScaling | configurations', ['aws', 'auto_scaling_m']) do + + params = { + :id => uniq_id, + :image_id => 'ami-8c1fece5', + :instance_type => 't1.micro' + } + + collection_tests(Fog::AWS[:auto_scaling].configurations, params, false) + +end diff --git a/tests/models/auto_scaling/groups_test.rb b/tests/models/auto_scaling/groups_test.rb new file mode 100644 index 000000000..7cd8f222d --- /dev/null +++ b/tests/models/auto_scaling/groups_test.rb @@ -0,0 +1,27 @@ +Shindo.tests('Aws::AutoScaling | group', ['aws', 'auto_scaling_m']) do + + params = { + :id => uniq_id, + :auto_scaling_group_name => "name", + :availability_zones => [], + :launch_configuration_name => "lc" + } + + lc_params = { + :id => params[:launch_configuration_name], + :image_id => "image-id", + :instance_type => "instance-type", + } + + Fog::AWS[:auto_scaling].configurations.new(lc_params).save + + model_tests(Fog::AWS[:auto_scaling].groups, params, true) do + @instance.update + end + + test("setting attributes in the constructor") do + group = Fog::AWS[:auto_scaling].groups.new(:min_size => 1, :max_size => 2) + group.min_size == 1 && group.max_size == 2 + end + +end diff --git a/tests/models/auto_scaling/helper.rb b/tests/models/auto_scaling/helper.rb new file mode 100644 index 000000000..e69de29bb diff --git a/tests/models/auto_scaling/instance_tests.rb b/tests/models/auto_scaling/instance_tests.rb new file mode 100644 index 000000000..2d280df16 --- /dev/null +++ b/tests/models/auto_scaling/instance_tests.rb @@ -0,0 +1,15 @@ +require 'fog/aws/models/auto_scaling/instance' + +Shindo.tests("Fog::AWS::AutoScaling::Instance", 'aws') do + @instance = Fog::AWS::AutoScaling::Instance.new + + test('#healthy? = true') do + @instance.health_status = 'Healthy' + @instance.healthy? == true + end + + test('#heatlhy? = false') do + @instance.health_status = 'Unhealthy' + @instance.healthy? == false + end +end diff --git a/tests/models/auto_scaling/instances_tests.rb b/tests/models/auto_scaling/instances_tests.rb new file mode 100644 index 000000000..3b5232ce1 --- /dev/null +++ b/tests/models/auto_scaling/instances_tests.rb @@ -0,0 +1,6 @@ +Shindo.tests('Aws::AutoScaling | instances', ['aws', 'auto_scaling_m']) do + + pending # FIXME: instance#save is not defined + #collection_tests(Fog::AWS[:auto_scaling].instances, {}, false) + +end diff --git a/tests/models/beanstalk/application_tests.rb b/tests/models/beanstalk/application_tests.rb new file mode 100644 index 000000000..980077bca --- /dev/null +++ b/tests/models/beanstalk/application_tests.rb @@ -0,0 +1,69 @@ +Shindo.tests("Fog::AWS[:beanstalk] | application", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @application_opts = { + :name => uniq_id('fog-test-app'), + :description => 'A nice description.' + } + + model_tests(Fog::AWS[:beanstalk].applications, @application_opts, false) do + + test("#attributes") do + @instance.name == @application_opts[:name] && + @instance.description == @application_opts[:description] + end + + test("#events") do + # There should be some events now. + @instance.events.length > 0 + end + + version_name = uniq_id('fog-test-ver') + @instance.versions.create( + :application_name => @instance.name, + :label => version_name + ) + + test("#versions") do + # We should have one version. + @instance.versions.length == 1 + end + + template_name = uniq_id('fog-test-template') + @instance.templates.create( + :application_name => @instance.name, + :name => template_name, + :solution_stack_name => '32bit Amazon Linux running Tomcat 7' + ) + + test('#templates') do + # We should have one template now. + @instance.templates.length == 1 + end + + environment_name = uniq_id('fog-test-env') + environment = @instance.environments.create( + :application_name => @instance.name, + :name => environment_name, + :version_label => version_name, + :solution_stack_name => '32bit Amazon Linux running Tomcat 7' + ) + + # Go ahead an terminate immediately. + environment.destroy + + # Create an environment + test("#environments") do + # We should have one environment now. + @instance.environments.length == 1 + end + + # Must wait for termination before destroying application + tests("waiting for test environment to terminate").succeeds do + environment.wait_for { terminated? } + end + + end + +end diff --git a/tests/models/beanstalk/applications_tests.rb b/tests/models/beanstalk/applications_tests.rb new file mode 100644 index 000000000..77978867f --- /dev/null +++ b/tests/models/beanstalk/applications_tests.rb @@ -0,0 +1,7 @@ +Shindo.tests("Fog::AWS[:beanstalk] | applications", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + collection_tests(Fog::AWS[:beanstalk].applications, {:name => uniq_id('fog-test-app')}, false) + +end diff --git a/tests/models/beanstalk/environment_tests.rb b/tests/models/beanstalk/environment_tests.rb new file mode 100644 index 000000000..44caf3fb1 --- /dev/null +++ b/tests/models/beanstalk/environment_tests.rb @@ -0,0 +1,131 @@ +Shindo.tests("Fog::AWS[:beanstalk] | environment", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @beanstalk = Fog::AWS[:beanstalk] + + @application_name = uniq_id('fog-test-app') + @environment_name = uniq_id('fog-test-env') + @version_names = [] + # Create two unique version names + 2.times { + @version_names << uniq_id('fog-test-version') + } + + @application = @beanstalk.applications.create({:name => @application_name}) + + @versions = [] + @version_names.each { |name| + @versions << @beanstalk.versions.create({ + :label => name, + :application_name => @application_name, + }) + } + + @environment_opts = { + :application_name => @application_name, + :name => @environment_name, + :version_label => @version_names[0], + :solution_stack_name => '32bit Amazon Linux running Tomcat 7' + } + + # Note: These model tests can take quite a bit of time to run, about 10 minutes typically. + model_tests(@beanstalk.environments, @environment_opts, false) do + # Wait for initial ready before next tests. + tests("#ready?").succeeds do + @instance.wait_for { ready? } + end + + tests("#healthy?").succeeds do + @instance.wait_for { healthy? } + end + + test("#events") do + # There should be some events now. + @instance.events.length > 0 + end + + test("#version") do + @instance.version.label == @version_names[0] + end + + test("#version= string") do + # Set to version 2 + @instance.version = @version_names[1] + + count = 0 + if @instance.version.label == @version_names[1] + @instance.events.each { |event| + if event.message == "Environment update is starting." + count = count + 1 + end + } + end + + count == 1 + end + + tests("#ready? after version= string").succeeds do + @instance.wait_for { ready? } + end + + test("#version= version object") do + # reset back to first version using version object + @instance.version = @versions[0] + + count = 0 + if @instance.version.label == @version_names[0] + @instance.events.each { |event| + if event.message == "Environment update is starting." + count = count + 1 + end + } + end + + # Pass if we have two environment updating events + count == 2 + end + + tests("#ready? after version= version object").succeeds do + @instance.wait_for { ready? } + end + + test('#restart_app_server') do + @instance.restart_app_server + + passed = false + @instance.events.each { |event| + if event.message == "restartAppServer is starting." + passed = true + end + } + passed + end + + test('#rebuild') do + @instance.rebuild + passed = false + @instance.events.each { |event| + if event.message == "rebuildEnvironment is starting." + passed = true + end + } + passed + end + + # Wait for ready or next tests may fail + tests("#ready? after rebuild").succeeds do + @instance.wait_for { ready? } + end + + end + + # Wait for instance to terminate before deleting application + tests('#terminated?').succeeds do + @instance.wait_for { terminated? } + end + + # delete application + @application.destroy + +end diff --git a/tests/models/beanstalk/environments_tests.rb b/tests/models/beanstalk/environments_tests.rb new file mode 100644 index 000000000..3f87059f3 --- /dev/null +++ b/tests/models/beanstalk/environments_tests.rb @@ -0,0 +1,34 @@ +Shindo.tests("Fog::AWS[:beanstalk] | environments", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @beanstalk = Fog::AWS[:beanstalk] + + @application_name = uniq_id('fog-test-app') + @environment_name = uniq_id('fog-test-env') + @version_name = uniq_id('fog-test-version') + + # Create an application/version to use for testing. + @version = @beanstalk.versions.create({ + :label => @version_name, + :application_name => @application_name, + :auto_create_application => true + }) + + @application = @beanstalk.applications.get(@application_name) + + @environment_opts = { + :application_name => @application_name, + :name => @environment_name, + :version_label => @version_name, + :solution_stack_name => '32bit Amazon Linux running Tomcat 7' + } + + collection_tests(@beanstalk.environments, @environment_opts, false) + + # Wait for instance to terminate before deleting application + @instance.wait_for { terminated? } + # delete application + @application.destroy + +end diff --git a/tests/models/beanstalk/template_tests.rb b/tests/models/beanstalk/template_tests.rb new file mode 100644 index 000000000..a65f0e648 --- /dev/null +++ b/tests/models/beanstalk/template_tests.rb @@ -0,0 +1,47 @@ +Shindo.tests("Fog::AWS[:beanstalk] | template", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @beanstalk = Fog::AWS[:beanstalk] + + @application_name = uniq_id('fog-test-app') + @template_name = uniq_id('fog-test-template') + + @template_description = 'A nice description' + + @application = @beanstalk.applications.create({:name => @application_name}) + + @template_opts = { + :application_name => @application_name, + :name => @template_name, + :description => @template_description, + :solution_stack_name => '32bit Amazon Linux running Tomcat 7' + } + + model_tests(@beanstalk .templates, @template_opts, false) do + + test("#attributes") do + @instance.name == @template_name && + @instance.description == @template_description && + @instance.application_name == @application_name && + @instance.solution_stack_name == @template_opts[:solution_stack_name] + end + + test("#options") do + options = @instance.options + passed = false + if options.each { |option| + # See if we recognize at least one option + if option["Name"] == 'LoadBalancerHTTPPort' && option["Namespace"] == 'aws:elb:loadbalancer' + passed = true + end + } + end + passed + end + + end + + # delete application + @application.destroy +end diff --git a/tests/models/beanstalk/templates_tests.rb b/tests/models/beanstalk/templates_tests.rb new file mode 100644 index 000000000..600e329d4 --- /dev/null +++ b/tests/models/beanstalk/templates_tests.rb @@ -0,0 +1,62 @@ +Shindo.tests("Fog::AWS[:beanstalk] | templates", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @beanstalk = Fog::AWS[:beanstalk] + + @application_name = uniq_id('fog-test-app') + @template_name = uniq_id('fog-test-template') + + @template_description = 'A nice description' + + @application = @beanstalk.applications.create({:name => @application_name}) + + params = { + :application_name => @application_name, + :name => @template_name, + :description => @template_description, + :solution_stack_name => '32bit Amazon Linux running Tomcat 7' + } + + collection = @beanstalk.templates + + tests('success') do + + tests("#new(#{params.inspect})").succeeds do + pending if Fog.mocking? + collection.new(params) + end + + tests("#create(#{params.inspect})").succeeds do + pending if Fog.mocking? + @instance = collection.create(params) + end + + tests("#all").succeeds do + pending if Fog.mocking? + collection.all + end + + tests("#get(#{@application_name}, #{@template_name})").succeeds do + pending if Fog.mocking? + collection.get(@application_name, @template_name) + end + + if !Fog.mocking? + @instance.destroy + end + end + + tests('failure') do + + tests("#get(#{@application_name}, #{@template_name})").returns(nil) do + pending if Fog.mocking? + collection.get(@application_name, @template_name) + end + + end + + # delete application + @application.destroy + +end diff --git a/tests/models/beanstalk/version_tests.rb b/tests/models/beanstalk/version_tests.rb new file mode 100644 index 000000000..2758eafa5 --- /dev/null +++ b/tests/models/beanstalk/version_tests.rb @@ -0,0 +1,66 @@ +Shindo.tests("Fog::AWS[:beanstalk] | version", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @beanstalk = Fog::AWS[:beanstalk] + + @application_name = uniq_id('fog-test-app') + @version_name = uniq_id('fog-test-version') + + @version_description = 'A nice description' + + @application = @beanstalk.applications.create({:name => @application_name}) + + @version_opts = { + :application_name => @application_name, + :label => @version_name, + :description => @version_description + } + + model_tests(@beanstalk.versions, @version_opts, false) do + + test("attributes") do + @instance.label == @version_name && + @instance.description == @version_description && + @instance.application_name == @application_name + end + + test("#events") do + # There should be some events now. + @instance.events.length > 0 + end + + test("#update description") do + new_description = "A completely new description." + @instance.description = new_description + @instance.update + + passed = false + if @instance.description == new_description + # reload version from Aws to verify save is committed to server, not just on local object + if @beanstalk.versions.get(@application_name, @version_name).description == new_description + passed = true + end + end + passed + end + + test("#update description empty") do + @instance.description = '' # Set to empty to nil out + @instance.update + + passed = false + if @instance.description == nil + # reload version from Aws to verify save is committed to server, not just on local object + if @beanstalk.versions.get(@application_name, @version_name).description == nil + passed = true + end + end + passed + end + + end + + # delete application + @application.destroy +end diff --git a/tests/models/beanstalk/versions_tests.rb b/tests/models/beanstalk/versions_tests.rb new file mode 100644 index 000000000..5845bcda8 --- /dev/null +++ b/tests/models/beanstalk/versions_tests.rb @@ -0,0 +1,60 @@ +Shindo.tests("Fog::AWS[:beanstalk] | versions", ['aws', 'beanstalk']) do + + pending if Fog.mocking? + + @beanstalk = Fog::AWS[:beanstalk] + + @application_name = uniq_id('fog-test-app') + @version_name = uniq_id('fog-test-version') + + @version_description = 'A nice description' + + @application = @beanstalk.applications.create({:name => @application_name}) + + params = { + :application_name => @application_name, + :label => @version_name, + :description => @version_description + } + + collection = @beanstalk.versions + + tests('success') do + + tests("#new(#{params.inspect})").succeeds do + pending if Fog.mocking? + collection.new(params) + end + + tests("#create(#{params.inspect})").succeeds do + pending if Fog.mocking? + @instance = collection.create(params) + end + + tests("#all").succeeds do + pending if Fog.mocking? + collection.all + end + + tests("#get(#{@application_name}, #{@version_name})").succeeds do + pending if Fog.mocking? + collection.get(@application_name, @version_name) + end + + if !Fog.mocking? + @instance.destroy + end + end + + tests('failure') do + + tests("#get(#{@application_name}, #{@version_name})").returns(nil) do + pending if Fog.mocking? + collection.get(@application_name, @version_name) + end + + end + + # delete application + @application.destroy +end diff --git a/tests/models/cdn/distribution_tests.rb b/tests/models/cdn/distribution_tests.rb new file mode 100644 index 000000000..9b15695d9 --- /dev/null +++ b/tests/models/cdn/distribution_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests("Fog::CDN[:aws] | distribution", ['aws', 'cdn']) do + params = { :s3_origin => { 'DNSName' => 'fog_test_cdn.s3.amazonaws.com'}, :enabled => true } + model_tests(Fog::CDN[:aws].distributions, params, true) do + # distribution needs to be ready before being disabled + tests("#ready? - may take 15 minutes to complete...").succeeds do + @instance.wait_for { ready? } + end + + # and disabled before being distroyed + tests("#disable - may take 15 minutes to complete...").succeeds do + @instance.disable + @instance.wait_for { ready? } + end + end +end diff --git a/tests/models/cdn/distributions_tests.rb b/tests/models/cdn/distributions_tests.rb new file mode 100644 index 000000000..e665aed53 --- /dev/null +++ b/tests/models/cdn/distributions_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests("Fog::CDN[:aws] | distributions", ['aws', 'cdn']) do + params = { :s3_origin => { 'DNSName' => 'fog_test_cdn.s3.amazonaws.com'}, :enabled => true} + collection_tests(Fog::CDN[:aws].distributions, params, true) do + # distribution needs to be ready before being disabled + tests("#ready? - may take 15 minutes to complete...").succeeds do + @instance.wait_for { ready? } + end + + # and disabled before being distroyed + tests("#disable - may take 15 minutes to complete...").succeeds do + @instance.disable + @instance.wait_for { ready? } + end + end +end diff --git a/tests/models/cdn/invalidation_tests.rb b/tests/models/cdn/invalidation_tests.rb new file mode 100644 index 000000000..3bc94a037 --- /dev/null +++ b/tests/models/cdn/invalidation_tests.rb @@ -0,0 +1,31 @@ +Shindo.tests("Fog::CDN[:aws] | invalidation", ['aws', 'cdn']) do + + tests("distributions#create").succeeds do + @distribution = Fog::CDN[:aws].distributions.create(:s3_origin => {'DNSName' => 'fog_test.s3.amazonaws.com'}, :enabled => true) + end + + params = { :paths => [ '/index.html', '/path/to/index.html' ] } + + model_tests(@distribution.invalidations, params, true) do + + tests("#id") do + returns(true) { @instance.identity != nil } + end + + tests("#paths") do + returns([ '/index.html', '/path/to/index.html' ].sort) { @instance.paths.sort } + end + + tests("#ready? - may take 15 minutes to complete...").succeeds do + @instance.wait_for { ready? } + end + end + + tests("distribution#destroy - may take around 15/20 minutes to complete...").succeeds do + @distribution.wait_for { ready? } + @distribution.disable + @distribution.wait_for { ready? } + @distribution.destroy + end + +end diff --git a/tests/models/cdn/invalidations_tests.rb b/tests/models/cdn/invalidations_tests.rb new file mode 100644 index 000000000..dee9ab57b --- /dev/null +++ b/tests/models/cdn/invalidations_tests.rb @@ -0,0 +1,14 @@ +Shindo.tests("Fog::CDN[:aws] | invalidations", ['aws', 'cdn']) do + tests("distributions#create").succeeds do + @distribution = Fog::CDN[:aws].distributions.create(:s3_origin => {'DNSName' => 'fog_test.s3.amazonaws.com'}, :enabled => true) + end + + collection_tests(@distribution.invalidations, { :paths => [ '/index.html' ]}, true) + + tests("distribution#destroy - may take 15/20 minutes to complete").succeeds do + @distribution.wait_for { ready? } + @distribution.disable + @distribution.wait_for { ready? } + @distribution.destroy + end +end diff --git a/tests/models/cdn/streaming_distribution_tests.rb b/tests/models/cdn/streaming_distribution_tests.rb new file mode 100644 index 000000000..ebc8510bf --- /dev/null +++ b/tests/models/cdn/streaming_distribution_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests("Fog::CDN[:aws] | streaming_distribution", ['aws', 'cdn']) do + params = { :s3_origin => { 'DNSName' => 'fog_test_cdn.s3.amazonaws.com'}, :enabled => true } + model_tests(Fog::CDN[:aws].streaming_distributions, params, true) do + # distribution needs to be ready before being disabled + tests("#ready? - may take 15 minutes to complete...").succeeds do + @instance.wait_for { ready? } + end + + # and disabled before being distroyed + tests("#disable - may take 15 minutes to complete...").succeeds do + @instance.disable + @instance.wait_for { ready? } + end + end +end diff --git a/tests/models/cdn/streaming_distributions_tests.rb b/tests/models/cdn/streaming_distributions_tests.rb new file mode 100644 index 000000000..c00e1d10a --- /dev/null +++ b/tests/models/cdn/streaming_distributions_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests("Fog::CDN[:aws] | streaming_distributions", ['aws', 'cdn']) do + params = { :s3_origin => { 'DNSName' => 'fog_test_cdn.s3.amazonaws.com'}, :enabled => true} + collection_tests(Fog::CDN[:aws].streaming_distributions, params, true) do + # distribution needs to be ready before being disabled + tests("#ready? - may take 15 minutes to complete...").succeeds do + @instance.wait_for { ready? } + end + + # and disabled before being distroyed + tests("#disable - may take 15 minutes to complete...").succeeds do + @instance.disable + @instance.wait_for { ready? } + end + end +end diff --git a/tests/models/cloud_watch/alarm_data_tests.rb b/tests/models/cloud_watch/alarm_data_tests.rb new file mode 100644 index 000000000..06b0103d7 --- /dev/null +++ b/tests/models/cloud_watch/alarm_data_tests.rb @@ -0,0 +1,42 @@ +Shindo.tests("Aws::CloudWatch | alarm_data", ['aws', 'cloudwatch']) do + + pending if Fog.mocking? + + tests('success') do + tests("#all").succeeds do + Fog::AWS[:cloud_watch].alarm_data.all + end + + alarm_name_prefix = {'AlarmNamePrefix'=>'tmp'} + tests("#all_by_prefix").succeeds do + Fog::AWS[:cloud_watch].alarm_data.all(alarm_name_prefix) + end + + namespace = 'Aws/EC2' + metric_name = 'CPUUtilization' + + tests("#get").succeeds do + Fog::AWS[:cloud_watch].alarm_data.get(namespace, metric_name).to_json + end + + new_attributes = { + :alarm_name => 'tmp-alarm', + :comparison_operator => 'GreaterThanOrEqualToThreshold', + :evaluation_periods => 1, + :metric_name => 'tmp-metric-alarm', + :namespace => 'fog-0.11.0', + :period => 60, + :statistic => 'Sum', + :threshold => 5 + } + tests('#new').returns(new_attributes) do + Fog::AWS[:cloud_watch].alarm_data.new(new_attributes).attributes + end + + tests('#create').returns(new_attributes) do + Fog::AWS[:cloud_watch].alarm_data.create(new_attributes).attributes + end + + end + +end diff --git a/tests/models/cloud_watch/alarm_history_tests.rb b/tests/models/cloud_watch/alarm_history_tests.rb new file mode 100644 index 000000000..c881c9aa8 --- /dev/null +++ b/tests/models/cloud_watch/alarm_history_tests.rb @@ -0,0 +1,22 @@ +Shindo.tests("Aws::CloudWatch | alarm_histories", ['aws', 'cloudwatch']) do + + pending if Fog.mocking? + + tests('success') do + tests("#all").succeeds do + Fog::AWS[:cloud_watch].alarm_histories.all + end + + new_attributes = { + :alarm_name => 'tmp-alarm', + :end_date => '', + :history_item_type => 'StateUpdate', + :max_records => 1, + :start_date => '' + } + tests('#new').returns(new_attributes) do + Fog::AWS[:cloud_watch].alarm_histories.new(new_attributes).attributes + end + end + +end diff --git a/tests/models/cloud_watch/metric_statistics_tests.rb b/tests/models/cloud_watch/metric_statistics_tests.rb new file mode 100644 index 000000000..44e6e9552 --- /dev/null +++ b/tests/models/cloud_watch/metric_statistics_tests.rb @@ -0,0 +1,51 @@ +Shindo.tests("Aws::CloudWatch | metric_statistics", ['aws', 'cloudwatch']) do + + tests('success') do + pending if Fog.mocking? + + instanceId = 'i-420c352f' + metricName = 'DiskReadBytes' + namespace = 'Aws/EC2' + startTime = (Time.now-600).iso8601 + endTime = Time.now.iso8601 + period = 60 + statisticTypes = ['Minimum','Maximum','Sum','SampleCount','Average'] + + tests("#all").succeeds do + @statistics = Fog::AWS[:cloud_watch].metric_statistics.all({'Statistics' => statisticTypes, 'StartTime' => startTime, 'EndTime' => endTime, 'Period' => period, 'MetricName' => metricName, 'Namespace' => namespace, 'Dimensions' => [{'Name' => 'InstanceId', 'Value' => instanceId}]}) + end + + tests("#all_not_empty").returns(true) do + @statistics.length > 0 + end + + new_attributes = { + :namespace => 'Custom/Test', + :metric_name => 'ModelTest', + :value => 9, + :unit => 'None' + } + tests('#new').returns(new_attributes) do + Fog::AWS[:cloud_watch].metric_statistics.new(new_attributes).attributes + end + + tests('#create').returns(new_attributes) do + Fog::AWS[:cloud_watch].metric_statistics.create(new_attributes).attributes + end + + stats_set_attributes = { + :namespace => 'Custom/Test', + :metric_name => 'ModelTest', + :minimum => 0, + :maximum => 4, + :sum => 10, + :sample_count => 5, + :average => 2, + :unit => 'None' + } + tests('#create_stats_set').returns(stats_set_attributes) do + Fog::AWS[:cloud_watch].metric_statistics.create(stats_set_attributes).attributes + end + end + +end diff --git a/tests/models/cloud_watch/metrics_tests.rb b/tests/models/cloud_watch/metrics_tests.rb new file mode 100644 index 000000000..61165f4e0 --- /dev/null +++ b/tests/models/cloud_watch/metrics_tests.rb @@ -0,0 +1,32 @@ +Shindo.tests("Aws::CloudWatch | metrics", ['aws', 'cloudwatch']) do + + tests('success') do + pending # FIXME: the hardcoded instance id won't be available + tests("#all").succeeds do + Fog::AWS[:cloud_watch].metrics.all + end + instanceId = 'i-fd713391' + metricName = 'CPUUtilization' + namespace = 'Aws/EC2' + tests("#get").returns({:dimensions=>[{"Name"=>"InstanceId", "Value"=>instanceId}], :name=>metricName, :namespace=>namespace}) do + Fog::AWS[:cloud_watch].metrics.get(namespace, metricName, {'InstanceId' => instanceId}).attributes + end + + end + + tests('#each') do + Fog.mock! + tests("handle NextToken").returns(1001) do + count = 0 + Fog::AWS[:cloud_watch].metrics.each {|e| count += 1 } + count + end + + tests("yields Metrics instances").succeeds do + all = [] + Fog::AWS[:cloud_watch].metrics.each {|e| all << e } + all.all? {|e| e.is_a?(Fog::AWS::CloudWatch::Metric) } + end + end + +end diff --git a/tests/models/compute/address_tests.rb b/tests/models/compute/address_tests.rb new file mode 100644 index 000000000..eeb1d397c --- /dev/null +++ b/tests/models/compute/address_tests.rb @@ -0,0 +1,24 @@ +Shindo.tests("Fog::Compute[:aws] | address", ['aws']) do + + model_tests(Fog::Compute[:aws].addresses, {}, true) do + + @server = Fog::Compute[:aws].servers.create + @server.wait_for { ready? } + + tests('#server=').succeeds do + @instance.server = @server + end + + tests('#server') do + test(' == @server') do + @server.reload + @instance.server.public_ip_address == @instance.public_ip + end + end + + @server.destroy + + end + + model_tests(Fog::Compute[:aws].addresses, { :domain => "vpc" }, true) +end diff --git a/tests/models/compute/addresses_tests.rb b/tests/models/compute/addresses_tests.rb new file mode 100644 index 000000000..c12dbbf0d --- /dev/null +++ b/tests/models/compute/addresses_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Fog::Compute[:aws] | addresses", ['aws']) do + + collection_tests(Fog::Compute[:aws].addresses, {}, true) + +end diff --git a/tests/models/compute/dhcp_option_tests.rb b/tests/models/compute/dhcp_option_tests.rb new file mode 100644 index 000000000..2a649a117 --- /dev/null +++ b/tests/models/compute/dhcp_option_tests.rb @@ -0,0 +1,3 @@ +Shindo.tests("Fog::Compute[:aws] | dhcp_options", ['aws']) do + model_tests(Fog::Compute[:aws].dhcp_options, {'dhcp_configuration_set' => {'domain-name' => 'example.com', 'domain-name-servers' => '10.10.10.10'}}, true) +end diff --git a/tests/models/compute/dhcp_options_tests.rb b/tests/models/compute/dhcp_options_tests.rb new file mode 100644 index 000000000..273309a7e --- /dev/null +++ b/tests/models/compute/dhcp_options_tests.rb @@ -0,0 +1,3 @@ +Shindo.tests("Fog::Compute[:aws] | dhcp_options", ['aws']) do + collection_tests(Fog::Compute[:aws].dhcp_options, {'dhcp_configuration_set' => {'domain-name' => 'example.com', 'domain-name-servers' => '10.10.10.10'}}, true) +end diff --git a/tests/models/compute/internet_gateway_tests.rb b/tests/models/compute/internet_gateway_tests.rb new file mode 100644 index 000000000..c35d22c27 --- /dev/null +++ b/tests/models/compute/internet_gateway_tests.rb @@ -0,0 +1,3 @@ +Shindo.tests("Fog::Compute[:aws] | internet_gateway", ['aws']) do + model_tests(Fog::Compute[:aws].internet_gateways , {}, true) +end diff --git a/tests/models/compute/internet_gateways_tests.rb b/tests/models/compute/internet_gateways_tests.rb new file mode 100644 index 000000000..868c0b6f9 --- /dev/null +++ b/tests/models/compute/internet_gateways_tests.rb @@ -0,0 +1,3 @@ +Shindo.tests("Fog::Compute[:aws] | internet_gateways", ['aws']) do + collection_tests(Fog::Compute[:aws].internet_gateways, {}, true) +end diff --git a/tests/models/compute/key_pair_tests.rb b/tests/models/compute/key_pair_tests.rb new file mode 100644 index 000000000..1a4680624 --- /dev/null +++ b/tests/models/compute/key_pair_tests.rb @@ -0,0 +1,26 @@ +Shindo.tests("Fog::Compute[:aws] | key_pair", ['aws']) do + + model_tests(Fog::Compute[:aws].key_pairs, {:name => 'fogkeyname'}, true) + + after do + @keypair.destroy + end + + tests("new keypair") do + @keypair = Fog::Compute[:aws].key_pairs.create(:name => 'testkey') + + test ("writable?") do + @keypair.writable? == true + end + end + + tests("existing keypair") do + Fog::Compute[:aws].key_pairs.create(:name => 'testkey') + @keypair = Fog::Compute[:aws].key_pairs.get('testkey') + + test("writable?") do + @keypair.writable? == false + end + end + +end diff --git a/tests/models/compute/key_pairs_tests.rb b/tests/models/compute/key_pairs_tests.rb new file mode 100644 index 000000000..3924418d0 --- /dev/null +++ b/tests/models/compute/key_pairs_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Fog::Compute[:aws] | key_pairs", ['aws']) do + + collection_tests(Fog::Compute[:aws].key_pairs, {:name => 'fogkeyname'}, true) + +end diff --git a/tests/models/compute/network_acl_tests.rb b/tests/models/compute/network_acl_tests.rb new file mode 100644 index 000000000..05d16b893 --- /dev/null +++ b/tests/models/compute/network_acl_tests.rb @@ -0,0 +1,109 @@ +Shindo.tests("Fog::Compute[:aws] | network_acl", ['aws']) do + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @subnet = Fog::Compute[:aws].subnets.create('vpc_id' => @vpc.id, 'cidr_block' => '10.0.10.16/28') + + model_tests(Fog::Compute[:aws].network_acls, { :vpc_id => @vpc.id }, true) + + tests("associate_with") do + @new_nacl = Fog::Compute[:aws].network_acls.create(:vpc_id => @vpc.id) + @default_nacl = Fog::Compute[:aws].network_acls.all('vpc-id' => @vpc.id, 'default' => true).first + + test("associate_with new_nacl") do + @new_nacl.associate_with(@subnet) + end + + @new_nacl.reload + + test("associate_with correctly updates new_nacl") do + @new_nacl.associations.map { |a| a['subnetId'] } == [@subnet.subnet_id] + end + + @default_nacl.associate_with(@subnet) + @new_nacl.reload + @default_nacl.reload + + test("associate_with correctly updates new_nacl after removal") do + @new_nacl.associations.map { |a| a['subnetId'] } == [] + end + + test("associate_with correctly updates default_nacl after removal") do + @default_nacl.associations.map { |a| a['subnetId'] } == [@subnet.subnet_id] + end + + @new_nacl.destroy + end + + tests("add_rule and remove_rule") do + @new_nacl = Fog::Compute[:aws].network_acls.create(:vpc_id => @vpc.id) + default_rules = @new_nacl.entries.dup + + test("add a new inbound rule") do + @new_nacl.add_inbound_rule(100, Fog::Compute::AWS::NetworkAcl::TCP, 'allow', '0.0.0.0/0', 'PortRange.From' => 22, 'PortRange.To' => 22) + @new_nacl.reload + (@new_nacl.entries - default_rules) == [{ + "icmpTypeCode" => {}, + "portRange" => { + "from" => 22, + "to" => 22 + }, + "ruleNumber" => 100, + "protocol" => 6, + "ruleAction" => "allow", + "egress" => false, + "cidrBlock" => "0.0.0.0/0" + }] + end + + test("remove inbound rule") do + @new_nacl.remove_inbound_rule(100) + @new_nacl.reload + @new_nacl.entries == default_rules + end + + test("add a new outbound rule") do + @new_nacl.add_outbound_rule(100, Fog::Compute::AWS::NetworkAcl::TCP, 'allow', '0.0.0.0/0', 'PortRange.From' => 22, 'PortRange.To' => 22) + @new_nacl.reload + (@new_nacl.entries - default_rules) == [{ + "icmpTypeCode" => {}, + "portRange" => { + "from" => 22, + "to" => 22 + }, + "ruleNumber" => 100, + "protocol" => 6, + "ruleAction" => "allow", + "egress" => true, + "cidrBlock" => "0.0.0.0/0" + }] + end + + test("remove outbound rule") do + @new_nacl.remove_outbound_rule(100) + @new_nacl.reload + @new_nacl.entries == default_rules + end + + test("update rule") do + @new_nacl.add_inbound_rule(100, Fog::Compute::AWS::NetworkAcl::TCP, 'allow', '0.0.0.0/0', 'PortRange.From' => 22, 'PortRange.To' => 22) + @new_nacl.update_inbound_rule(100, Fog::Compute::AWS::NetworkAcl::TCP, 'allow', '10.0.0.0/8', 'PortRange.From' => 22, 'PortRange.To' => 22) + @new_nacl.reload + (@new_nacl.entries - default_rules) == [{ + "icmpTypeCode" => {}, + "portRange" => { + "from" => 22, + "to" => 22 + }, + "ruleNumber" => 100, + "protocol" => 6, + "ruleAction" => "allow", + "egress" => false, + "cidrBlock" => "10.0.0.0/8" + }] + end + + @new_nacl.destroy + end + + @subnet.destroy + @vpc.destroy +end diff --git a/tests/models/compute/network_acls_tests.rb b/tests/models/compute/network_acls_tests.rb new file mode 100644 index 000000000..c8fc1bf97 --- /dev/null +++ b/tests/models/compute/network_acls_tests.rb @@ -0,0 +1,20 @@ +Shindo.tests("Fog::Compute[:aws] | network_acls", ['aws']) do + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + + collection_tests(Fog::Compute[:aws].network_acls, { :vpc_id => @vpc.id }, true) + + tests('tags') do + test_tags = {'foo' => 'bar'} + @acl = Fog::Compute[:aws].network_acls.create(:vpc_id => @vpc.id, :tags => test_tags) + + tests('@acl.tags').returns(test_tags) do + @acl.reload.tags + end + + unless Fog.mocking? + Fog::Compute[:aws].tags.all('resource-id' => @acl.identity).each {|tag| tag.destroy} + end + end + + @vpc.destroy +end diff --git a/tests/models/compute/network_interfaces_test.rb b/tests/models/compute/network_interfaces_test.rb new file mode 100644 index 000000000..6fdfa597f --- /dev/null +++ b/tests/models/compute/network_interfaces_test.rb @@ -0,0 +1,12 @@ +Shindo.tests("Fog::Compute[:aws] | network_interfaces", ['aws']) do + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @subnet = Fog::Compute[:aws].subnets.create('vpc_id' => @vpc.id, 'cidr_block' => '10.0.10.16/28') + @subnet_id = @subnet.subnet_id + + collection_tests(Fog::Compute[:aws].network_interfaces, + {:description => 'nic_desc', :name => 'nic_name', :subnet_id => @subnet_id}, + true) + + @subnet.destroy + @vpc.destroy +end diff --git a/tests/models/compute/security_group_tests.rb b/tests/models/compute/security_group_tests.rb new file mode 100644 index 000000000..9c0c49290 --- /dev/null +++ b/tests/models/compute/security_group_tests.rb @@ -0,0 +1,64 @@ +Shindo.tests("Fog::Compute[:aws] | security_group", ['aws']) do + + model_tests(Fog::Compute[:aws].security_groups, {:description => 'foggroupdescription', :name => 'foggroupname'}, true) + + tests("authorize and revoke helpers") do + @group = Fog::Compute[:aws].security_groups.create(:name => "foggroup", :description => "fog group desc") + + @other_group = Fog::Compute[:aws].security_groups.create(:name => 'fog other group', :description => 'another fog group') + @other_group.reload + + @other_user_id = Fog::AWS::Mock.owner_id + @other_users_group_id = Fog::AWS::Mock.security_group_id + + test("authorize access by another security group") do + @group.authorize_group_and_owner(@other_group.name) + @group.reload + @group.ip_permissions.size == 3 + end + + test("revoke access from another security group") do + @group.revoke_group_and_owner(@other_group.name) + @group.reload + @group.ip_permissions.empty? + end + + test("authorize access to a port range") do + @group.authorize_port_range(5000..6000) + @group.reload + @group.ip_permissions.size == 1 + end + + test("revoke access to a port range") do + @group.revoke_port_range(5000..6000) + @group.reload + @group.ip_permissions.empty? + end + + group_forms = [ + "#{@other_group.owner_id}:#{@other_group.group_id}", # deprecated form + @other_group.group_id, + {@other_group.owner_id => @other_group.group_id}, + {@other_user_id => @other_users_group_id} + ] + + group_forms.each do |group_arg| + test("authorize port range access by another security group #{group_arg.inspect}") do + @other_group.reload + @group.authorize_port_range(5000..6000, {:group => group_arg}) + @group.reload + @group.ip_permissions.size == 1 + end + + test("revoke port range access by another security group") do + @other_group.reload + @group.revoke_port_range(5000..6000, {:group => group_arg}) + @group.reload + @group.ip_permissions.empty? + end + end + + @other_group.destroy + @group.destroy + end +end diff --git a/tests/models/compute/security_groups_tests.rb b/tests/models/compute/security_groups_tests.rb new file mode 100644 index 000000000..9af8c0509 --- /dev/null +++ b/tests/models/compute/security_groups_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Fog::Compute[:aws] | security_groups", ['aws']) do + + collection_tests(Fog::Compute[:aws].security_groups, {:description => 'foggroupdescription', :name => 'foggroupname'}, true) + +end diff --git a/tests/models/compute/server_tests.rb b/tests/models/compute/server_tests.rb new file mode 100644 index 000000000..6ed018946 --- /dev/null +++ b/tests/models/compute/server_tests.rb @@ -0,0 +1,83 @@ +Shindo.tests("Fog::Compute[:aws] | monitor", ['aws']) do + + @instance = Fog::Compute[:aws].servers.new + + [:addresses, :flavor, :key_pair, :key_pair=, :volumes, :associate_public_ip].each do |association| + responds_to(association) + end + + tests('new instance') do + + test('#monitor = true') do + @instance.monitor = true + @instance.attributes[:monitoring] == true + end + + test('#monitor = false') do + @instance.monitor = false + @instance.attributes[:monitoring] == false + end + + test('#associate_public_ip = true') do + @instance.associate_public_ip = true + @instance.attributes[:associate_public_ip] == true + end + + test('#associate_public_ip = false') do + @instance.associate_public_ip = false + @instance.associate_public_ip == false + end + + end + + tests('existing instance') do + + @instance.save + + [:id, :availability_zone, :flavor_id, :kernel_id, :image_id, :state].each do |attr| + test("instance##{attr} should not contain whitespace") do + nil == @instance.send(attr).match(/\s/) + end + end + + test('#monitor = true') do + @instance.monitor = true + @instance.monitoring == true + end + + test('#monitor = false') do + @instance.monitor = false + @instance.monitoring == false + end + + test('#associate_public_ip = true') do + @instance.associate_public_ip = true + @instance.attributes[:associate_public_ip] == true + end + + test('#associate_public_ip = false') do + @instance.associate_public_ip = false + @instance.associate_public_ip == false + end + + end + + @instance.destroy + + tests('tags') do + @instance = Fog::Compute[:aws].servers.create(:tags => {'key' => 'value'}) + + @instance.wait_for { ready? } + + tests('@instance.reload.tags').returns({'key' => 'value'}) do + @instance.reload.tags + end + + unless Fog.mocking? + Fog::Compute[:aws].tags.all('resource-id' => @instance.identity).each {|tag| tag.destroy} + end + + @instance.destroy + end + +end diff --git a/tests/models/compute/snapshot_tests.rb b/tests/models/compute/snapshot_tests.rb new file mode 100644 index 000000000..ddceed7ca --- /dev/null +++ b/tests/models/compute/snapshot_tests.rb @@ -0,0 +1,10 @@ +Shindo.tests("Fog::Compute[:aws] | snapshot", ['aws']) do + + @volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1a', :size => 1) + @volume.wait_for { ready? } + + model_tests(Fog::Compute[:aws].snapshots, {:volume_id => @volume.identity}, true) + + @volume.destroy + +end diff --git a/tests/models/compute/snapshots_tests.rb b/tests/models/compute/snapshots_tests.rb new file mode 100644 index 000000000..13d52c8e9 --- /dev/null +++ b/tests/models/compute/snapshots_tests.rb @@ -0,0 +1,10 @@ +Shindo.tests("Fog::Compute[:aws] | snapshots", ['aws']) do + + @volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1a', :size => 1) + @volume.wait_for { ready? } + + collection_tests(Fog::Compute[:aws].snapshots, {:volume_id => @volume.identity}, true) + + @volume.destroy + +end diff --git a/tests/models/compute/subnet_tests.rb b/tests/models/compute/subnet_tests.rb new file mode 100644 index 000000000..a578a5701 --- /dev/null +++ b/tests/models/compute/subnet_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Fog::Compute[:aws] | subnet", ['aws']) do + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + model_tests(Fog::Compute[:aws].subnets, {:vpc_id => @vpc.id, :cidr_block => '10.0.10.0/28', :availability_zone => 'us-east-1b'}, true) + @vpc.destroy +end diff --git a/tests/models/compute/subnets_tests.rb b/tests/models/compute/subnets_tests.rb new file mode 100644 index 000000000..81cee464f --- /dev/null +++ b/tests/models/compute/subnets_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Fog::Compute[:aws] | subnets", ['aws']) do + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/28') + collection_tests(Fog::Compute[:aws].subnets, { :vpc_id => @vpc.id, :cidr_block => '10.0.10.0/28', :availability_zone => 'us-east-1c'}, true) + @vpc.destroy +end diff --git a/tests/models/compute/volume_tests.rb b/tests/models/compute/volume_tests.rb new file mode 100644 index 000000000..fd902c7fb --- /dev/null +++ b/tests/models/compute/volume_tests.rb @@ -0,0 +1,43 @@ +Shindo.tests("Fog::Compute[:aws] | volume", ['aws']) do + + @server = Fog::Compute[:aws].servers.create + @server.wait_for { ready? } + + model_tests(Fog::Compute[:aws].volumes, {:availability_zone => @server.availability_zone, :size => 1, :device => '/dev/sdz1', :tags => {"key" => "value"}}, true) do + + @instance.wait_for { ready? } + + tests('#server = @server').succeeds do + @instance.server = @server + end + + @instance.wait_for { state == 'in-use' } + + tests('#server').succeeds do + @instance.server.id == @server.id + end + + tests('#server = nil').succeeds do + (@instance.server = nil).nil? + end + + @instance.wait_for { ready? } + + @instance.server = @server + @instance.wait_for { state == 'in-use' } + + tests('#force_detach').succeeds do + @instance.force_detach + end + + @instance.wait_for { ready? } + + tests('@instance.reload.tags').returns({'key' => 'value'}) do + @instance.reload.tags + end + + end + + @server.destroy + +end diff --git a/tests/models/compute/volumes_tests.rb b/tests/models/compute/volumes_tests.rb new file mode 100644 index 000000000..d2f22698c --- /dev/null +++ b/tests/models/compute/volumes_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Fog::Compute[:aws] | volumes", ['aws']) do + + collection_tests(Fog::Compute[:aws].volumes, {:availability_zone => 'us-east-1a', :size => 1, :device => '/dev/sdz1'}, true) + +end diff --git a/tests/models/compute/vpc_tests.rb b/tests/models/compute/vpc_tests.rb new file mode 100644 index 000000000..c111e06fc --- /dev/null +++ b/tests/models/compute/vpc_tests.rb @@ -0,0 +1,4 @@ +Shindo.tests("Fog::Compute[:aws] | vpc", ['aws']) do + + model_tests(Fog::Compute[:aws].vpcs, {:cidr_block => '10.0.10.0/28'}, true) +end diff --git a/tests/models/compute/vpcs_tests.rb b/tests/models/compute/vpcs_tests.rb new file mode 100644 index 000000000..05db09c03 --- /dev/null +++ b/tests/models/compute/vpcs_tests.rb @@ -0,0 +1,19 @@ +Shindo.tests("Fog::Compute[:aws] | vpcs", ['aws']) do + + collection_tests(Fog::Compute[:aws].vpcs, {:cidr_block => '10.0.10.0/28'}, true) + + tests('tags') do + test_tags = {'foo' => 'bar'} + @vpc = Fog::Compute[:aws].vpcs.create(:cidr_block => '1.2.3.4/24', :tags => test_tags) + + tests('@vpc.tags').returns(test_tags) do + @vpc.reload.tags + end + + unless Fog.mocking? + Fog::Compute[:aws].tags.all('resource-id' => @vpc.id).each {|tag| tag.destroy} + end + + @vpc.destroy + end +end diff --git a/tests/models/data_pipeline/pipeline_tests.rb b/tests/models/data_pipeline/pipeline_tests.rb new file mode 100644 index 000000000..322b19bd6 --- /dev/null +++ b/tests/models/data_pipeline/pipeline_tests.rb @@ -0,0 +1,8 @@ +Shindo.tests("Aws::DataPipeline | pipelines", ['aws', 'data_pipeline']) do + pending if Fog.mocking? + + unique_id = uniq_id + model_tests(Fog::AWS[:data_pipeline].pipelines, { :id => unique_id, :name => "#{unique_id}-name", :unique_id => unique_id }) do + @instance.wait_for { state } + end +end diff --git a/tests/models/data_pipeline/pipelines_tests.rb b/tests/models/data_pipeline/pipelines_tests.rb new file mode 100644 index 000000000..b16bf9e90 --- /dev/null +++ b/tests/models/data_pipeline/pipelines_tests.rb @@ -0,0 +1,8 @@ +Shindo.tests("Aws::DataPipeline | pipelines", ['aws', 'data_pipeline']) do + pending if Fog.mocking? + + unique_id = uniq_id + collection_tests(Fog::AWS[:data_pipeline].pipelines, { :id => unique_id, :name => "#{unique_id}-name", :unique_id => unique_id }) do + @instance.wait_for { state } + end +end diff --git a/tests/models/dns/record_tests.rb b/tests/models/dns/record_tests.rb new file mode 100644 index 000000000..0c695c6b9 --- /dev/null +++ b/tests/models/dns/record_tests.rb @@ -0,0 +1,33 @@ +Shindo.tests("Fog::Dns[:aws] | record", ['aws', 'dns']) do + + tests("zones#create").succeeds do + @zone = Fog::DNS[:aws].zones.create(:domain => generate_unique_domain) + end + + params = { :name => @zone.domain, :type => 'A', :ttl => 3600, :value => ['1.2.3.4'] } + + model_tests(@zone.records, params) do + + # Newly created records should have a change id + tests("#change_id") do + returns(true) { @instance.change_id != nil } + end + + # Waits for changes to sync to all Route 53 DNS servers. Usually takes ~30 seconds to complete. + tests("#ready? - may take a minute to complete...").succeeds do + @instance.wait_for { ready? } + end + + tests("#modify") do + new_value = ['5.5.5.5'] + returns(true) { @instance.modify(:value => new_value) } + returns(new_value) { @instance.value } + end + + end + + tests("zones#destroy").succeeds do + @zone.destroy + end + +end diff --git a/tests/models/dns/records_tests.rb b/tests/models/dns/records_tests.rb new file mode 100644 index 000000000..d9e9b736f --- /dev/null +++ b/tests/models/dns/records_tests.rb @@ -0,0 +1,41 @@ +Shindo.tests("Fog::DNS[:aws] | records", ['aws', 'dns']) do + + tests("zones#create").succeeds do + @zone = Fog::DNS[:aws].zones.create(:domain => generate_unique_domain) + end + + param_groups = [ + # A record + { :name => @zone.domain, :type => 'A', :ttl => 3600, :value => ['1.2.3.4'] }, + # CNAME record + { :name => "www.#{@zone.domain}", :type => "CNAME", :ttl => 300, :value => @zone.domain} + ] + + param_groups.each do |params| + collection_tests(@zone.records, params) + end + + records = [] + + 100.times do |i| + records << @zone.records.create(:name => "#{i}.#{@zone.domain}", :type => "A", :ttl => 3600, :value => ['1.2.3.4']) + end + + records << @zone.records.create(:name => "*.#{@zone.domain}", :type => "A", :ttl => 3600, :value => ['1.2.3.4']) + + tests("#all!").returns(101) do + @zone.records.all!.size + end + + tests("#all wildcard parsing").returns(true) do + @zone.records.map(&:name).include?("*.#{@zone.domain}") + end + + records.each do |record| + record.destroy + end + + tests("zones#destroy").succeeds do + @zone.destroy + end +end diff --git a/tests/models/dns/zone_tests.rb b/tests/models/dns/zone_tests.rb new file mode 100644 index 000000000..1c473d89b --- /dev/null +++ b/tests/models/dns/zone_tests.rb @@ -0,0 +1,4 @@ +Shindo.tests("Fog::DNS[:aws] | zone", ['aws', 'dns']) do + params = {:domain => generate_unique_domain } + model_tests(Fog::DNS[:aws].zones, params) +end diff --git a/tests/models/dns/zones_tests.rb b/tests/models/dns/zones_tests.rb new file mode 100644 index 000000000..a770cd7fe --- /dev/null +++ b/tests/models/dns/zones_tests.rb @@ -0,0 +1,4 @@ +Shindo.tests("Fog::DNS[:aws] | zones", ['aws', 'dns']) do + params = {:domain => generate_unique_domain } + collection_tests(Fog::DNS[:aws].zones, params) +end diff --git a/tests/models/elasticache/cluster_tests.rb b/tests/models/elasticache/cluster_tests.rb new file mode 100644 index 000000000..07f920d1d --- /dev/null +++ b/tests/models/elasticache/cluster_tests.rb @@ -0,0 +1,30 @@ +Shindo.tests('Aws::Elasticache | cache clusters', ['aws', 'elasticache']) do + cluster_params = { + :id => "fog-test-cluster-#{rand(999).to_s}", + :node_type => 'cache.m1.large', + :security_groups => ['default'], + :engine => 'memcached', + :num_nodes => 1 + } + + pending if Fog.mocking? + + Formatador.display_line "Creating cluster #{cluster_params[:id]}..." + model_tests(Aws[:elasticache].clusters, cluster_params, false) do + @instance.reload # Reload to get the cluster info from Aws + Formatador.display_line "Waiting for #{@instance.id} "+ + "to become available (#{@instance.status})..." + @instance.wait_for {ready?} + end + + # Single model is still deleting, so re-randomize the cluster ID + cluster_params[:id] = "fog-test-cluster-#{rand(999).to_s}" + Formatador.display_line "Creating cluster #{cluster_params[:id]}..." + collection_tests(Aws[:elasticache].clusters, cluster_params, false) do + @instance.reload # Reload to get the cluster info from Aws + Formatador.display_line "Waiting for #{@instance.id} "+ + "to become available (#{@instance.status})..." + @instance.wait_for {ready?} + end + +end diff --git a/tests/models/elasticache/parameter_groups_tests.rb b/tests/models/elasticache/parameter_groups_tests.rb new file mode 100644 index 000000000..aa1b78b63 --- /dev/null +++ b/tests/models/elasticache/parameter_groups_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests('Aws::Elasticache | parameter groups', ['aws', 'elasticache']) do + group_name = 'fog-test' + description = 'Fog Test' + + model_tests( + Aws[:elasticache].parameter_groups, + {:id => group_name, :description => description}, true + ) + + collection_tests( + Aws[:elasticache].parameter_groups, + {:id => group_name, :description => description}, true + ) + +end diff --git a/tests/models/elasticache/security_groups_tests.rb b/tests/models/elasticache/security_groups_tests.rb new file mode 100644 index 000000000..0b9531adf --- /dev/null +++ b/tests/models/elasticache/security_groups_tests.rb @@ -0,0 +1,52 @@ +Shindo.tests('Aws::Elasticache | security groups', ['aws', 'elasticache']) do + group_name = 'fog-test' + description = 'Fog Test' + + pending if Fog.mocking? + + model_tests( + Aws[:elasticache].security_groups, + {:id => group_name, :description => description}, false + ) do + + # An EC2 group to authorize + ec2_group = Fog::Compute.new(:provider => 'Aws').security_groups.create( + :name => 'fog-test-elasticache', :description => 'fog test' + ) + + # Reload to get the instance owner_id + @instance.reload + + tests('#authorize_ec2_group') do + @instance.authorize_ec2_group(ec2_group.name) + returns('authorizing') do + group = @instance.ec2_groups.find do |g| + g['EC2SecurityGroupName'] == ec2_group.name + end + group['Status'] + end + returns(false, 'not ready') { @instance.ready? } + end + + @instance.wait_for { ready? } + + tests('#revoke_ec2_group') do + @instance.revoke_ec2_group(ec2_group.name) + returns('revoking') do + group = @instance.ec2_groups.find do |g| + g['EC2SecurityGroupName'] == ec2_group.name + end + group['Status'] + end + returns(false, 'not ready') { @instance.ready? } + end + + ec2_group.destroy + end + + collection_tests( + Aws[:elasticache].security_groups, + {:id => group_name, :description => description}, false + ) + +end diff --git a/tests/models/elasticache/subnet_groups_tests.rb b/tests/models/elasticache/subnet_groups_tests.rb new file mode 100644 index 000000000..2febf2e73 --- /dev/null +++ b/tests/models/elasticache/subnet_groups_tests.rb @@ -0,0 +1,44 @@ +Shindo.tests('Aws::Elasticache | subnet group', ['aws', 'elasticache']) do + # random_differentiator + # Useful when rapidly re-running tests, so we don't have to wait + # serveral minutes for deleted VPCs/subnets to disappear + suffix = rand(65536).to_s(16) + @subnet_group_name = "fog-test-#{suffix}" + + vpc_range = rand(245) + 10 + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => "10.#{vpc_range}.0.0/16") + + # Create 4 subnets in this VPC, each one in a different AZ + subnet_az = 'us-east-1a' + subnet_range = 8 + @subnets = (1..3).map do + result = Fog::Compute[:aws].create_subnet(@vpc.id, "10.#{vpc_range}.#{subnet_range}.0/24", + 'AvailabilityZone' => subnet_az) + puts result + subnet = result.body['subnet'] + subnet_az = subnet_az.succ + subnet_range *= 2 + subnet + end + + tests('success') do + group_name = 'fog-test' + description = 'Fog Test' + subnet_ids = @subnets.map { |sn| sn['subnetId'] }.to_a + + model_tests( + Aws[:elasticache].subnet_groups, + {:name => group_name, :subnet_ids => subnet_ids, :description => description}, true + ) + + collection_tests( + Aws[:elasticache].subnet_groups, + {:name => group_name, :subnet_ids => subnet_ids, :description => description}, true + ) + end + + @subnets.each do |sn| + Fog::Compute[:aws].delete_subnet(sn['subnetId']) + end + @vpc.destroy +end diff --git a/tests/models/elb/model_tests.rb b/tests/models/elb/model_tests.rb new file mode 100644 index 000000000..19881b7d8 --- /dev/null +++ b/tests/models/elb/model_tests.rb @@ -0,0 +1,360 @@ +Shindo.tests('Aws::ELB | models', ['aws', 'elb']) do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + @availability_zones = Fog::Compute[:aws].describe_availability_zones('state' => 'available').body['availabilityZoneInfo'].map{ |az| az['zoneName'] } + @key_name = 'fog-test-model' + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @vpc_id = @vpc.id + @subnet = Fog::Compute[:aws].subnets.create({:vpc_id => @vpc_id, :cidr_block => '10.0.10.0/24'}) + @subnet_id = @subnet.subnet_id + @scheme = 'internal' + @igw = Fog::Compute[:aws].internet_gateways.create + @igw_id = @igw.id + @igw.attach(@vpc_id) + + tests('success') do + tests('load_balancers') do + tests('getting a missing elb') do + returns(nil) { Fog::AWS[:elb].load_balancers.get('no-such-elb') } + end + end + + tests('listeners') do + tests("default attributes") do + listener = Fog::AWS[:elb].listeners.new + tests('instance_port is 80').returns(80) { listener.instance_port } + tests('instance_protocol is HTTP').returns('HTTP') { listener.instance_protocol } + tests('lb_port is 80').returns(80) { listener.lb_port } + tests('protocol is HTTP').returns('HTTP') { listener.protocol } + tests('policy_names is empty').returns([]) { listener.policy_names } + end + + tests("specifying attributes") do + attributes = {:instance_port => 2000, :instance_protocol => 'SSL', :lb_port => 2001, :protocol => 'SSL', :policy_names => ['fake'] } + listener = Fog::AWS[:elb].listeners.new(attributes) + tests('instance_port is 2000').returns(2000) { listener.instance_port } + tests('instance_protocol is SSL').returns('SSL') { listener.instance_protocol } + tests('lb_port is 2001').returns(2001) { listener.lb_port } + tests('protocol is SSL').returns('SSL') { listener.protocol } + tests('policy_names is [ fake ]').returns(['fake']) { listener.policy_names } + end + end + + elb = nil + elb_id = 'fog-test' + + tests('create') do + tests('without availability zones') do + elb = Fog::AWS[:elb].load_balancers.create(:id => elb_id, :availability_zones => @availability_zones) + tests("availability zones are correct").returns(@availability_zones.sort) { elb.availability_zones.sort } + tests("dns names is set").returns(true) { elb.dns_name.is_a?(String) } + tests("created_at is set").returns(true) { Time === elb.created_at } + tests("policies is empty").returns([]) { elb.policies } + tests("default listener") do + tests("1 listener").returns(1) { elb.listeners.size } + tests("params").returns(Fog::AWS[:elb].listeners.new.to_params) { elb.listeners.first.to_params } + end + end + tests('with vpc') do + elb2 = Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-2", :subnet_ids => [@subnet_id]) + tests("elb source group should be default").returns('default') { elb2.source_group["GroupName"] } + tests("subnet ids are correct").returns(@subnet_id) { elb2.subnet_ids.first } + elb2.destroy + end + tests('with vpc internal') do + elb2 = Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-2", :subnet_ids => [@subnet_id], :scheme => 'internal') + tests("scheme is internal").returns(@scheme) { elb2.scheme } + elb2.destroy + end + tests('with default vpc') do + Fog::Compute[:aws].disable_ec2_classic if Fog.mocking? + + if Fog::Compute[:aws].supported_platforms.include?("EC2") + Formatador.display_line("[yellow]Skipping test [bold]with default vpc[/][yellow] due to Aws account having EC2 available[/]") + else + elb2 = Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-2", :availability_zones => @availability_zones[0]) + tests("elb source group should start with default_elb_").returns(true) { !!(elb2.source_group["GroupName"] =~ /default_elb_/) } + elb2.destroy + end + + Fog::Compute[:aws].enable_ec2_classic if Fog.mocking? + end + + if !Fog.mocking? + @igw.detach(@vpc_id) + @igw.destroy + @subnet.destroy + sleep 5 + @vpc.destroy + end + + tests('with availability zones') do + azs = @availability_zones[1..-1] + elb2 = Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-2", :availability_zones => azs) + if Fog::Compute[:aws].supported_platforms.include?("EC2") + tests("elb source group should be amazon-elb-sg").returns('amazon-elb-sg') { elb2.source_group["GroupName"] } + else + tests("elb source group should match default_elb_").returns(true) { !!(elb2.source_group["GroupName"] =~ /default_elb_/) } + end + tests("availability zones are correct").returns(azs.sort) { elb2.availability_zones.sort } + elb2.destroy + end + + # Need to sleep here for IAM changes to propgate + tests('with ListenerDescriptions') do + @certificate = Fog::AWS[:iam].upload_server_certificate(Aws::IAM::SERVER_CERT, Aws::IAM::SERVER_CERT_PRIVATE_KEY, @key_name).body['Certificate'] + sleep(10) unless Fog.mocking? + listeners = [{ + 'Listener' => { + 'LoadBalancerPort' => 2030, 'InstancePort' => 2030, 'Protocol' => 'HTTP' + }, + 'PolicyNames' => [] + }, { + 'Listener' => { + 'LoadBalancerPort' => 443, 'InstancePort' => 443, 'Protocol' => 'HTTPS', 'InstanceProtocol' => 'HTTPS', + 'SSLCertificateId' => @certificate['Arn'] + }, + 'PolicyNames' => [] + }] + elb3 = Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-3", 'ListenerDescriptions' => listeners, :availability_zones => @availability_zones) + tests('there are 2 listeners').returns(2) { elb3.listeners.count } + tests('instance_port is 2030').returns(2030) { elb3.listeners.first.instance_port } + tests('lb_port is 2030').returns(2030) { elb3.listeners.first.lb_port } + tests('protocol is HTTP').returns('HTTP') { elb3.listeners.first.protocol } + tests('protocol is HTTPS').returns('HTTPS') { elb3.listeners.last.protocol } + tests('instance_protocol is HTTPS').returns('HTTPS') { elb3.listeners.last.instance_protocol } + elb3.destroy + end + + tests('with invalid Server Cert ARN').raises(Fog::AWS::IAM::NotFound) do + listeners = [{ + 'Listener' => { + 'LoadBalancerPort' => 443, 'InstancePort' => 80, 'Protocol' => 'HTTPS', 'InstanceProtocol' => 'HTTPS', "SSLCertificateId" => "fakecert"} + }] + Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-4", "ListenerDescriptions" => listeners, :availability_zones => @availability_zones) + end + end + + tests('all') do + elb_ids = Fog::AWS[:elb].load_balancers.all.map{|e| e.id} + tests("contains elb").returns(true) { elb_ids.include? elb_id } + end + + if Fog.mocking? + tests('all marker support') do + extra_elb_ids = (1..1000).map {|n| Fog::AWS[:elb].load_balancers.create(:id => "#{elb_id}-extra-#{n}").id } + tests('returns all elbs').returns(true) { (extra_elb_ids - Fog::AWS[:elb].load_balancers.all.map {|e| e.id }).empty? } + end + end + + tests('get') do + tests('ids match').returns(elb_id) { Fog::AWS[:elb].load_balancers.get(elb_id).id } + tests('nil id').returns(nil) { Fog::AWS[:elb].load_balancers.get(nil) } + end + + tests('creating a duplicate elb') do + raises(Fog::AWS::ELB::IdentifierTaken) do + Fog::AWS[:elb].load_balancers.create(:id => elb_id, :availability_zones => ['us-east-1d']) + end + end + + tests('registering an invalid instance') do + raises(Fog::AWS::ELB::InvalidInstance) { elb.register_instances('i-00000000') } + end + + tests('deregistering an invalid instance') do + raises(Fog::AWS::ELB::InvalidInstance) { elb.deregister_instances('i-00000000') } + end + + server = Fog::Compute[:aws].servers.create + server.wait_for { ready? } + + tests('register instance') do + begin + elb.register_instances(server.id) + rescue Fog::AWS::ELB::InvalidInstance + # It may take a moment for a newly created instances to be visible to ELB requests + raise if @retried_registered_instance + @retried_registered_instance = true + sleep 1 + retry + end + + returns([server.id]) { elb.instances } + end + + tests('instance_health') do + returns('OutOfService') do + elb.instance_health.find{|hash| hash['InstanceId'] == server.id}['State'] + end + + returns([server.id]) { elb.instances_out_of_service } + end + + tests('deregister instance') do + elb.deregister_instances(server.id) + returns([]) { elb.instances } + end + server.destroy + + tests('disable_availability_zones') do + elb.disable_availability_zones(@availability_zones[1..-1]) + returns(@availability_zones[0..0]) { elb.availability_zones.sort } + end + + tests('enable_availability_zones') do + elb.enable_availability_zones(@availability_zones[1..-1]) + returns(@availability_zones) { elb.availability_zones.sort } + end + + tests('connection_draining') do + returns(false) { elb.connection_draining? } + returns(300) { elb.connection_draining_timeout } + elb.set_connection_draining(true, 60) + returns(true) { elb.connection_draining? } + returns(60) { elb.connection_draining_timeout } + end + + tests('cross_zone_load_balancing') do + returns(false) {elb.cross_zone_load_balancing?} + elb.cross_zone_load_balancing = true + returns(true) {elb.cross_zone_load_balancing?} + end + + tests('idle_connection_settings') do + returns(60) { elb.connection_settings_idle_timeout } + elb.set_connection_settings_idle_timeout(180) + returns(180) { elb.connection_settings_idle_timeout } + end + + tests('default health check') do + default_health_check = { + "HealthyThreshold"=>10, + "Timeout"=>5, + "UnhealthyThreshold"=>2, + "Interval"=>30, + "Target"=>"TCP:80" + } + returns(default_health_check) { elb.health_check } + end + + tests('configure_health_check') do + new_health_check = { + "HealthyThreshold" => 5, + "Timeout" => 10, + "UnhealthyThreshold" => 3, + "Interval" => 15, + "Target" => "HTTP:80/index.html" + } + elb.configure_health_check(new_health_check) + returns(new_health_check) { elb.health_check } + end + + tests('listeners') do + tests('default') do + returns(1) { elb.listeners.size } + + listener = elb.listeners.first + returns([80,80,'HTTP','HTTP', []]) { [listener.instance_port, listener.lb_port, listener.protocol, listener.instance_protocol, listener.policy_names] } + end + + tests('#get') do + returns(80) { elb.listeners.get(80).lb_port } + end + + tests('create') do + elb.listeners.create(:instance_port => 443, :lb_port => 443, :protocol => 'TCP', :instance_protocol => 'TCP') + returns(2) { elb.listeners.size } + returns(443) { elb.listeners.get(443).lb_port } + end + + tests('destroy') do + elb.listeners.get(443).destroy + returns(nil) { elb.listeners.get(443) } + end + end + + tests('policies') do + app_policy_id = 'my-app-policy' + + tests 'are empty' do + returns([]) { elb.policies.to_a } + end + + tests('#all') do + returns([]) { elb.policies.all.to_a } + end + + tests('create app policy') do + elb.policies.create(:id => app_policy_id, :cookie => 'my-app-cookie', :cookie_stickiness => :app) + returns(app_policy_id) { elb.policies.first.id } + returns("my-app-cookie") { elb.policies.get(app_policy_id).cookie } + end + + tests('get policy') do + returns(app_policy_id) { elb.policies.get(app_policy_id).id } + end + + tests('destroy app policy') do + elb.policies.first.destroy + returns([]) { elb.policies.to_a } + end + + lb_policy_id = 'my-lb-policy' + tests('create lb policy') do + elb.policies.create(:id => lb_policy_id, :expiration => 600, :cookie_stickiness => :lb) + returns(lb_policy_id) { elb.policies.first.id } + end + + tests('setting a listener policy') do + elb.set_listener_policy(80, lb_policy_id) + returns([lb_policy_id]) { elb.listeners.get(80).policy_names } + returns(600) { elb.policies.get(lb_policy_id).expiration } + end + + tests('unsetting a listener policy') do + elb.unset_listener_policy(80) + returns([]) { elb.listeners.get(80).policy_names } + end + + public_key_policy_id = 'fog-public-key-policy' + tests('create public key policy') do + elb.policies.create(:id => public_key_policy_id, :type_name => 'PublicKeyPolicyType', :policy_attributes => {'PublicKey' => Aws::IAM::SERVER_CERT_PUBLIC_KEY}) + policy = elb.policies.get(public_key_policy_id) + + returns(public_key_policy_id) { policy.id } + returns("PublicKeyPolicyType") { policy.type_name } + returns(Aws::IAM::SERVER_CERT_PUBLIC_KEY) { policy.policy_attributes["PublicKey"] } + end + + tests('a malformed policy') do + raises(ArgumentError) { elb.policies.create(:id => 'foo', :cookie_stickiness => 'invalid stickiness') } + end + end + + tests('backend server descriptions') do + tests('default') do + returns(0) { elb.backend_server_descriptions.size } + end + + tests('with a backend policy') do + policy = "EnableProxyProtocol" + port = 80 + elb.policies.create(:id => policy, :type_name => 'ProxyProtocolPolicyType', :policy_attributes => { "ProxyProtocol" => true }) + Fog::AWS[:elb].set_load_balancer_policies_for_backend_server(elb.id, port, [policy]).body + elb.reload + returns([policy]) { elb.backend_server_descriptions.get(port).policy_names } + end + end + + tests('setting a new ssl certificate id') do + elb.listeners.create(:instance_port => 443, :lb_port => 443, :protocol => 'HTTPS', :instance_protocol => 'HTTPS', :ssl_id => @certificate['Arn']) + elb.set_listener_ssl_certificate(443, @certificate['Arn']) + end + + tests('destroy') do + elb.destroy + end + + Fog::AWS[:iam].delete_server_certificate(@key_name) + end +end diff --git a/tests/models/elb/tagging_tests.rb b/tests/models/elb/tagging_tests.rb new file mode 100644 index 000000000..b2faad868 --- /dev/null +++ b/tests/models/elb/tagging_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests("Aws::ELB | tagging", ['aws', 'elb']) do + @elb5 = Fog::AWS[:elb].load_balancers.create(:id => "fog-test-elb-tagging") + tags1 = {'key1' => 'val1'} + tags2 = {'key2' => 'val2'} + + tests "add and remove tags from an ELB" do + returns({}) { @elb5.tags } + returns(tags1) { @elb5.add_tags tags1 } + returns(tags1.merge tags2) { @elb5.add_tags tags2 } + returns(tags2) { @elb5.remove_tags tags1.keys } + returns(tags2) { @elb5.tags } + + @elb5.destroy + end +end diff --git a/tests/models/glacier/model_tests.rb b/tests/models/glacier/model_tests.rb new file mode 100644 index 000000000..31c302516 --- /dev/null +++ b/tests/models/glacier/model_tests.rb @@ -0,0 +1,47 @@ +Shindo.tests('Aws::Glacier | models', ['aws', 'glacier']) do + pending if Fog.mocking? + tests('success') do + tests('vaults') do + tests('getting a missing vault') do + returns(nil) { Fog::AWS[:glacier].vaults.get('no-such-vault') } + end + + vault = nil + tests('creating a vault') do + vault = Fog::AWS[:glacier].vaults.create :id => 'Fog-Test-Vault' + tests("id is Fog-Test-Vault").returns('Fog-Test-Vault') {vault.id} + end + + tests('all') do + tests('contains vault').returns(true) { Fog::AWS[:glacier].vaults.map {|vault| vault.id}.include?(vault.id)} + end + + tests('destroy') do + vault.destroy + tests('removes vault').returns(nil) {Fog::AWS[:glacier].vaults.get(vault.id)} + end + end + + tests("archives") do + vault = Fog::AWS[:glacier].vaults.create :id => 'Fog-Test-Vault-upload' + tests('create') do + archive = vault.archives.create(:body => 'data') + tests('sets id').returns(true) {!archive.id.nil?} + archive.destroy + end + tests('create multipart') do + body = StringIO.new('x'*1024*1024*2) + body.rewind + archive = vault.archives.create(:body => body, :multipart_chunk_size => 1024*1024) + tests('sets id').returns(true) {!archive.id.nil?} + archive.destroy + end + end + + vault = Fog::AWS[:glacier].vaults.create :id => 'Fog-Test-Vault' + tests("jobs") do + tests('all').returns([]) {vault.jobs} + end + vault.destroy + end +end diff --git a/tests/models/iam/access_keys_tests.rb b/tests/models/iam/access_keys_tests.rb new file mode 100644 index 000000000..e21757d15 --- /dev/null +++ b/tests/models/iam/access_keys_tests.rb @@ -0,0 +1,53 @@ +Shindo.tests("Fog::Compute[:iam] | access_keys", ['aws','iam']) do + + iam = Fog::AWS[:iam] + + @username = 'fake_user' + @user = iam.users.create(:id => @username) + + + tests('#all', 'there are no access keys for a new user').succeeds do + @user.access_keys.empty? + end + + + tests('#create','an access key').succeeds do + access_key = @user.access_keys.create + access_key.id =~ /[A-Z0-9]{20}/ + access_key.secret_access_key =~ /[\S]{40}/ + access_key.status == "Active" + access_key.username == @username + @access_key_id = access_key.id + end + + @user.access_keys.create + + tests('#all','there are two access keys').succeeds do + @user.access_keys.size == 2 + end + + tests('#get') do + tests('a valid access key id').succeeds do + access_key = @user.access_keys.get(@access_key_id) + access_key.id == @access_key_id + access_key.secret_access_key == nil + access_key.status == "Active" + access_key.username == @username + end + + tests('an invalid access key').succeeds do + @user.access_keys.get('non-existing') == nil + end + end + + tests('#destroy', 'decrease by one the number of access keys').succeeds do + size = @user.access_keys.size + @user.access_keys.get(@access_key_id).destroy + @user.access_keys.size == ( size - 1 ) + end + + # clean up + @user.access_keys.map(&:destroy) + @user.destroy + +end diff --git a/tests/models/iam/policies_tests.rb b/tests/models/iam/policies_tests.rb new file mode 100644 index 000000000..33b4ff1b0 --- /dev/null +++ b/tests/models/iam/policies_tests.rb @@ -0,0 +1,57 @@ +Shindo.tests("Fog::Compute[:iam] | policies", ['aws','iam']) do + + iam = Fog::AWS[:iam] + + @username = 'fake_user' + @user = iam.users.create(:id => @username) + @policy_document = {"Statement"=>[{"Action"=>["sqs:*"], "Effect"=>"Allow", "Resource"=>"*"}]} + @policy_name = 'fake-sqs-policy' + + tests('#all', 'there is no policies').succeeds do + @user.policies.empty? + end + + tests('#create') do + tests('a valid policy').succeeds do + policy = @user.policies.create(:id => @policy_name, :document => @policy_document) + policy.id == @policy_name + policy.username == @username + policy.document == @policy_document + end + + # The mocking doesn't validate the document policy + #tests('an invalid valid policy').succeeds do + # raises(Fog::AWS::IAM::Error) { @user.policies.create(id: 'non-valid-document', document: 'invalid json blob') } + #end + end + + @user.policies.create(:id => 'another-policy', :document => {}) + + tests('#all','there are two policies').succeeds do + @user.policies.size == 2 + end + + tests('#get') do + tests('a valid policy').succeeds do + policy = @user.policies.get(@policy_name) + policy.id == @polic_name + policy.username == @username + policy.document == @policy_document + end + + tests('an invalid policy').succeeds do + @user.policies.get('non-existing') == nil + end + end + + tests('#destroy').succeeds do + @user.policies.get(@policy_name).destroy + end + + # clean up + @user.access_keys.map(&:destroy) + @user.policies.map(&:destroy) + @user.destroy + + +end diff --git a/tests/models/iam/roles_tests.rb b/tests/models/iam/roles_tests.rb new file mode 100644 index 000000000..40da23edc --- /dev/null +++ b/tests/models/iam/roles_tests.rb @@ -0,0 +1,63 @@ +Shindo.tests("Fog::Compute[:iam] | roles", ['aws','iam']) do + + pending if Fog.mocking? + + @iam = Fog::AWS[:iam] + @role_one_name = 'fake_role_one' + @role_two_name = 'fake_role_two' + + @role_three_name = 'fake_role_three' + @role_three_path = '/path/to/fake_role_three/' + @role_four_name = 'fake_role_four' + + tests('#create').succeeds do + @role_one = @iam.roles.create(:rolename => @role_one_name) + @role_one.rolename == @role_one_name + end + + tests('#all','there is only one role').succeeds do + @iam.roles.size == 1 + end + + tests('#all','the only role should match').succeeds do + @iam.roles.first.rolename == @role_one_name + end + + tests('#create','a second role').succeeds do + @role_two = @iam.roles.create(:rolename => @role_two_name) + @role_two.rolename == @role_two_name + end + + tests('#all','there are two roles').succeeds do + @iam.roles.size == 2 + end + + tests('#get','an existing role').succeeds do + @iam.roles.get(@role_one_name).rolename == @role_one_name + end + + tests('#get',"returns nil if the role doesn't exists").succeeds do + @iam.roles.get('non-exists') == nil + end + + tests('#create', 'assigns path').succeeds do + @role_three = @iam.roles.create(:rolename => @role_three_name, :path => @role_three_path) + @role_three.path == @role_three_path + end + + tests('#create', 'defaults path to /').succeeds do + @role_four = @iam.roles.create(:rolename => @role_four_name) + @role_four.path == '/' + end + + tests('#destroy','an existing role').succeeds do + @iam.roles.get(@role_one_name).destroy + end + + tests('#destroy','clean up remaining roles').succeeds do + @iam.roles.get(@role_two_name).destroy + @iam.roles.get(@role_three_name).destroy + @iam.roles.get(@role_four_name).destroy + end + +end diff --git a/tests/models/iam/users_tests.rb b/tests/models/iam/users_tests.rb new file mode 100644 index 000000000..f44fb515a --- /dev/null +++ b/tests/models/iam/users_tests.rb @@ -0,0 +1,71 @@ +Shindo.tests("Fog::Compute[:iam] | users", ['aws','iam']) do + + @iam = Fog::AWS[:iam] + @user_one_name = 'fake_user_one' + @user_two_name = 'fake_user_two' + + @user_three_name = 'fake_user_three' + @user_three_path = '/path/to/fake_user_three/' + @user_four_name = 'fake_user_four' + + def all_users + @iam.users.all.select{|user| user.id =~ /^fake_user/ } + end + + tests('#create').succeeds do + @user_one = @iam.users.create(:id => @user_one_name) + @user_one.id == @user_one_name + end + + tests('#all','there is only one user').succeeds do + all_users.size == 1 + end + + tests('#all','the only user should match').succeeds do + all_users.first.id == @user_one_name + end + + tests('#create','a second user').succeeds do + @user_two = @iam.users.create(:id => @user_two_name) + @user_two.id == @user_two_name + end + + tests('#all','there are two users').succeeds do + all_users.size == 2 + end + + tests('#get','an existing user').succeeds do + @iam.users.get(@user_one_name).id == @user_one_name + end + + tests('#get',"returns nil if the user doesn't exists").succeeds do + @iam.users.get('non-exists') == nil + end + + tests('#policies','it has no policies').succeeds do + @iam.users.get(@user_one_name).policies.empty? + end + + tests('#access_keys','it has no keys').succeeds do + @iam.users.get(@user_one_name).access_keys.empty? + end + + tests('#create', 'assigns path').succeeds do + @user_three = @iam.users.create(:id => @user_three_name, :path => @user_three_path) + @user_three.path == @user_three_path + end + + tests('#create', 'defaults path to /').succeeds do + @user_four = @iam.users.create(:id => @user_four_name) + @user_four.path == '/' + end + + tests('#destroy','an existing user').succeeds do + @iam.users.get(@user_one_name).destroy + end + + tests('#destroy','clean up remaining user').succeeds do + @iam.users.get(@user_two_name).destroy + end + +end diff --git a/tests/models/rds/event_subscription_tests.rb b/tests/models/rds/event_subscription_tests.rb new file mode 100644 index 000000000..b3378ead2 --- /dev/null +++ b/tests/models/rds/event_subscription_tests.rb @@ -0,0 +1,9 @@ +Shindo.tests("Aws::RDS | event_subscription", ['aws', 'rds']) do + pending unless Fog.mocking? + + name = 'fog' + params = {:id => name, :sns_topic_arn => 'arn:aws:sns:us-east-1:12345678910:fog'} + + model_tests(Fog::AWS[:rds].event_subscriptions, params) do + end +end diff --git a/tests/models/rds/event_subscriptions_tests.rb b/tests/models/rds/event_subscriptions_tests.rb new file mode 100644 index 000000000..07659e49a --- /dev/null +++ b/tests/models/rds/event_subscriptions_tests.rb @@ -0,0 +1,6 @@ +Shindo.tests("Aws::RDS | event subscriptions", ['aws', 'rds']) do + pending unless Fog.mocking? + params = {:id => "fog", :sns_topic_arn => 'arn:aws:sns:us-east-1:12345678910:fog'} + + collection_tests(Fog::AWS[:rds].event_subscriptions, params) +end diff --git a/tests/models/rds/helper.rb b/tests/models/rds/helper.rb new file mode 100644 index 000000000..f874a7e12 --- /dev/null +++ b/tests/models/rds/helper.rb @@ -0,0 +1,5 @@ +def rds_default_server_params + { :id => uniq_id, :allocated_storage => 5, :engine => 'mysql', + :master_username => 'foguser', :password => 'fogpassword', + :backup_retention_period => 0 } +end diff --git a/tests/models/rds/instance_option_tests.rb b/tests/models/rds/instance_option_tests.rb new file mode 100644 index 000000000..afc85dcbc --- /dev/null +++ b/tests/models/rds/instance_option_tests.rb @@ -0,0 +1,14 @@ +Shindo.tests("Aws::RDS | db instance options", ['aws', 'rds']) do + + params = {:engine => 'mysql'} + + pending if Fog.mocking? + + tests('#options') do + tests 'contains options' do + @instance = Fog::AWS[:rds].instance_options.new(params) + returns(true) { @instance.engine == 'mysql' } + end + end + +end diff --git a/tests/models/rds/parameter_group_tests.rb b/tests/models/rds/parameter_group_tests.rb new file mode 100644 index 000000000..1bdf176df --- /dev/null +++ b/tests/models/rds/parameter_group_tests.rb @@ -0,0 +1,24 @@ +Shindo.tests("Aws::RDS | parameter_group", ['aws', 'rds']) do + + group_name = 'fog-test' + params = {:id => group_name, :family => 'mysql5.1', :description => group_name} + + pending if Fog.mocking? + model_tests(Fog::AWS[:rds].parameter_groups, params, false) do + tests('#parameters') do + #search for a sample parameter + tests 'contains parameters' do + returns(true){ @instance.parameters.any? {|p| p.name == 'query_cache_size'}} + end + end + + tests('#modify') do + @instance.modify([{:name => 'query_cache_size', :value => '6553600', :apply_method => 'immediate'}]) + + tests 'parameter has changed' do + returns('6553600'){@instance.parameters.find {|p| p.name == 'query_cache_size'}.value} + end + end + + end +end diff --git a/tests/models/rds/parameter_groups_tests.rb b/tests/models/rds/parameter_groups_tests.rb new file mode 100644 index 000000000..7ca1d2429 --- /dev/null +++ b/tests/models/rds/parameter_groups_tests.rb @@ -0,0 +1,8 @@ +Shindo.tests("Aws::RDS | parameter_groups", ['aws', 'rds']) do + + group_name = 'fog-test' + params = {:id => group_name, :family => 'mysql5.1', :description => group_name} + + pending if Fog.mocking? + collection_tests(Fog::AWS[:rds].parameter_groups, params, false) +end diff --git a/tests/models/rds/security_group_tests.rb b/tests/models/rds/security_group_tests.rb new file mode 100644 index 000000000..ebb7932b6 --- /dev/null +++ b/tests/models/rds/security_group_tests.rb @@ -0,0 +1,53 @@ +Shindo.tests("Aws::RDS | security_group", ['aws', 'rds']) do + group_name = 'fog-test' + params = {:id => group_name, :description => 'fog test'} + + model_tests(Fog::AWS[:rds].security_groups, params) do + + tests("#description").returns('fog test') { @instance.description } + + tests("#authorize_ec2_security_group").succeeds do + @ec2_sec_group = Fog::Compute[:aws].security_groups.create(:name => 'fog-test', :description => 'fog test') + + @instance.authorize_ec2_security_group(@ec2_sec_group.name) + returns('authorizing') do + @instance.ec2_security_groups.find{|h| h['EC2SecurityGroupName'] == @ec2_sec_group.name}['Status'] + end + end + + @instance.wait_for { ready? } + + tests("#revoke_ec2_security_group").succeeds do + pending if Fog.mocking? + + @instance.revoke_ec2_security_group(@ec2_sec_group.name) + + returns('revoking') do + @instance.ec2_security_groups.find{|h| h['EC2SecurityGroupName'] == @ec2_sec_group.name}['Status'] + end + + @instance.wait_for { ready? } + + returns(false) { @instance.ec2_security_groups.any?{|h| h['EC2SecurityGroupName'] == @ec2_sec_group.name} } + @ec2_sec_group.destroy + end + + tests("#authorize_cidrip").succeeds do + @cidr = '127.0.0.1/32' + @instance.authorize_cidrip(@cidr) + returns('authorizing') { @instance.ip_ranges.find{|h| h['CIDRIP'] == @cidr}['Status'] } + end + + tests("#revoke_cidrip").succeeds do + pending if Fog.mocking? + + @instance.wait_for { ready? } + @instance.revoke_cidrip(@cidr) + returns('revoking') { @instance.ip_ranges.find{|h| h['CIDRIP'] == @cidr}['Status'] } + @instance.wait_for { ready? } + returns(false) { @instance.ip_ranges.any?{|h| h['CIDRIP'] == @cidr} } + + end + + end +end diff --git a/tests/models/rds/security_groups_tests.rb b/tests/models/rds/security_groups_tests.rb new file mode 100644 index 000000000..0726f96bb --- /dev/null +++ b/tests/models/rds/security_groups_tests.rb @@ -0,0 +1,5 @@ +Shindo.tests("Aws::RDS | security groups", ['aws', 'rds']) do + params = {:id => 'fog-test', :description => 'fog test'} + + collection_tests(Fog::AWS[:rds].security_groups, params) +end diff --git a/tests/models/rds/server_tests.rb b/tests/models/rds/server_tests.rb new file mode 100644 index 000000000..e61c9f2ee --- /dev/null +++ b/tests/models/rds/server_tests.rb @@ -0,0 +1,110 @@ +Shindo.tests("Aws::RDS | server", ['aws', 'rds']) do + # Disabled due to https://github.com/fog/fog/1546 + pending + + model_tests(Fog::AWS[:rds].servers, rds_default_server_params) do + # We'll need this later; create it early to avoid waiting + @instance_with_final_snapshot = Fog::AWS[:rds].servers.create(rds_default_server_params.merge(:id => uniq_id("fog-snapshot-test"), :backup_retention_period => 1)) + + @instance.wait_for(20*60) { ready? } + + test('#read_replica_identifiers is []') do + returns([]) { @instance.read_replica_identifiers } + end + + tests('#snapshots') do + snapshot = nil + + tests('#create').succeeds do + snapshot = @instance.snapshots.create(:id => 'fog-test-snapshot') + end + + snapshot.wait_for { ready?} + + @instance.wait_for { ready? } + + returns(true) { @instance.snapshots.map{|s| s.id}.include?(snapshot.id) } + snapshot.destroy + end + + tests("#modify").succeeds do + pending if Fog.mocking? + + orig_parameter_group = @instance.db_parameter_groups.first['DBParameterGroupName'] + parameter_group = Fog::AWS[:rds].parameter_groups.create(:id => uniq_id, :family => 'mysql5.5', :description => 'fog-test') + + orig_security_groups = @instance.db_security_groups.map{|h| h['DBSecurityGroupName']} + security_group = Fog::AWS[:rds].security_groups.create(:id => uniq_id, :description => 'fog-test') + + modify_options = { + 'DBParameterGroupName' => parameter_group.id, + 'DBSecurityGroups' => orig_security_groups + [security_group.id] + } + + @instance.modify(true, modify_options) + @instance.wait_for { ready? } + + returns(parameter_group.id, 'new parameter group') do + @instance.db_parameter_groups.first['DBParameterGroupName'] + end + + returns(true, "new security group") do + @instance.db_security_groups.any?{|hash| hash['DBSecurityGroupName'] == security_group.id} + end + + @instance.reboot + @instance.wait_for { state == 'rebooting' } + @instance.wait_for { ready? } + + # Restore back to original state using symbols + restore_options = { + :parameter_group_name => orig_parameter_group, + :security_group_names => orig_security_groups + } + @instance.modify(true, restore_options) + + @instance.reboot + @instance.wait_for { state == 'rebooting' } + @instance.wait_for do + ready? && + db_security_groups.all? {|hash| hash['Status'] == 'active'} && + db_parameter_groups.all? {|hash| hash['ParameterApplyStatus'] == 'in-sync' } + end + + parameter_group.destroy + security_group.destroy + end + + tests("#reboot").succeeds do + @instance.reboot + end + @instance.wait_for { state == 'rebooting' } + @instance.wait_for { ready? } + + tests('#create_read_replica').succeeds do + + replica = @instance_with_final_snapshot.create_read_replica(uniq_id('fog-replica')) + @instance_with_final_snapshot.reload + returns([replica.id]) { @instance_with_final_snapshot.read_replica_identifiers } + returns(@instance_with_final_snapshot.id) { replica.read_replica_source } + + replica.wait_for { ready? } + replica.destroy + end + + test("Destroying with a final snapshot") do + final_snapshot_id = 'fog-test-snapshot' + + @instance_with_final_snapshot.wait_for { ready? } + @instance_with_final_snapshot.destroy(final_snapshot_id) + returns(true, "Final snapshot created") do + @final_snapshot = Fog::AWS[:rds].snapshots.get(final_snapshot_id) + !@final_snapshot.nil? + end + + @final_snapshot.wait_for { ready? } + @final_snapshot.destroy + end + + end +end diff --git a/tests/models/rds/servers_tests.rb b/tests/models/rds/servers_tests.rb new file mode 100644 index 000000000..d0be89602 --- /dev/null +++ b/tests/models/rds/servers_tests.rb @@ -0,0 +1,6 @@ +Shindo.tests("Aws::RDS | servers", ['aws', 'rds']) do + + collection_tests(Fog::AWS[:rds].servers, rds_default_server_params) do + @instance.wait_for { ready? } + end +end diff --git a/tests/models/rds/snapshot_tests.rb b/tests/models/rds/snapshot_tests.rb new file mode 100644 index 000000000..d2f0fc389 --- /dev/null +++ b/tests/models/rds/snapshot_tests.rb @@ -0,0 +1,12 @@ +Shindo.tests("Aws::RDS | snapshot", ['aws', 'rds']) do + + @server = Fog::AWS[:rds].servers.create(rds_default_server_params) + @server.wait_for { ready? } + + params = {:id => uniq_id, :instance_id => @server.id} + model_tests(Fog::AWS[:rds].snapshots, params) do + @instance.wait_for { ready? } + end + + @server.destroy +end diff --git a/tests/models/rds/snapshots_tests.rb b/tests/models/rds/snapshots_tests.rb new file mode 100644 index 000000000..4048d7226 --- /dev/null +++ b/tests/models/rds/snapshots_tests.rb @@ -0,0 +1,12 @@ +Shindo.tests("Aws::RDS | snapshots", ['aws', 'rds']) do + + @server = Fog::AWS[:rds].servers.create(rds_default_server_params) + @server.wait_for { ready? } + + params = {:id => uniq_id, :instance_id => @server.id} + collection_tests(Fog::AWS[:rds].snapshots, params) do + @instance.wait_for { ready? } + end + + @server.destroy +end diff --git a/tests/models/rds/tagging_tests.rb b/tests/models/rds/tagging_tests.rb new file mode 100644 index 000000000..ef8d762c4 --- /dev/null +++ b/tests/models/rds/tagging_tests.rb @@ -0,0 +1,20 @@ +Shindo.tests("Aws::RDS | tagging", ['aws', 'rds']) do + + @server = Fog::AWS[:rds].servers.create(rds_default_server_params) + Formatador.display_line "Creating RDS instance #{@server.id}" + Formatador.display_line "Waiting for instance #{@server.id} to be ready" + @server.wait_for { ready? } + + tags1 = {'key1' => 'val1'} + tags2 = {'key2' => 'val2'} + + tests "add and remove tags from a running RDS model" do + returns({}) { @server.tags } + returns(tags1) { @server.add_tags tags1 } + returns(tags1.merge tags2) { @server.add_tags tags2 } + returns(tags2) { @server.remove_tags tags1.keys } + returns(tags2) { @server.tags } + end + + @server.destroy +end diff --git a/tests/models/sns/topic_tests.rb b/tests/models/sns/topic_tests.rb new file mode 100644 index 000000000..8d80492fb --- /dev/null +++ b/tests/models/sns/topic_tests.rb @@ -0,0 +1,15 @@ +Shindo.tests("Aws::SNS | topic", ['aws', 'sns']) do + params = {:id => 'fog'} + + model_tests(Fog::AWS[:sns].topics, params) do + @instance.wait_for { ready? } + + tests("#display_name").returns('fog') { @instance.display_name } + + tests("#update_topic_attribute") do + @instance.update_topic_attribute("DisplayName", "new-fog") + + tests("#display_name").returns('new-fog') { @instance.display_name } + end + end +end diff --git a/tests/models/sns/topics_tests.rb b/tests/models/sns/topics_tests.rb new file mode 100644 index 000000000..bb26675cd --- /dev/null +++ b/tests/models/sns/topics_tests.rb @@ -0,0 +1,6 @@ +Shindo.tests("Aws::SNS | topics", ['aws', 'sns']) do + pending unless Fog.mocking? + params = {:id => 'arn:aws:sns:us-east-1:12345678910:fog'} + + collection_tests(Fog::AWS[:sns].topics, params) +end diff --git a/tests/models/storage/directory_tests.rb b/tests/models/storage/directory_tests.rb new file mode 100644 index 000000000..a26c4389d --- /dev/null +++ b/tests/models/storage/directory_tests.rb @@ -0,0 +1,87 @@ +Shindo.tests("Storage[:aws] | directory", ["aws"]) do + + directory_attributes = { + :key => uniq_id('fogdirectorytests') + } + + model_tests(Fog::Storage[:aws].directories, directory_attributes, Fog.mocking?) do + tests("#public_url").returns(nil) do + @instance.public_url + end + + @instance.acl = 'public-read' + @instance.save + + tests("#public_url").returns(true) do + if @instance.public_url =~ %r[\Ahttps://fogdirectorytests-[\da-f]+\.s3\.amazonaws\.com/\z] + true + else + @instance.public_url + end + end + end + + directory_attributes = { + :key => uniq_id('different-region'), + :location => 'eu-west-1', + } + + model_tests(Fog::Storage[:aws].directories, directory_attributes, Fog.mocking?) do + tests("#location").returns('eu-west-1') do + @instance.location + end + + tests("#location").returns('eu-west-1') do + Fog::Storage[:aws].directories.get(@instance.identity).location + end + end + + directory_attributes = { + :key => uniq_id('fogdirectorytests') + } + + model_tests(Fog::Storage[:aws].directories, directory_attributes, Fog.mocking?) do + + tests("#versioning=") do + tests("#versioning=(true)").succeeds do + @instance.versioning = true + end + + tests("#versioning=(true) sets versioning to 'Enabled'").returns('Enabled') do + @instance.versioning = true + @instance.service.get_bucket_versioning(@instance.key).body['VersioningConfiguration']['Status'] + end + + tests("#versioning=(false)").succeeds do + (@instance.versioning = false).equal? false + end + + tests("#versioning=(false) sets versioning to 'Suspended'").returns('Suspended') do + @instance.versioning = false + @instance.service.get_bucket_versioning(@instance.key).body['VersioningConfiguration']['Status'] + end + end + + end + + model_tests(Fog::Storage[:aws].directories, directory_attributes, Fog.mocking?) do + + tests("#versioning?") do + tests("#versioning? false if not enabled").returns(false) do + @instance.versioning? + end + + tests("#versioning? true if enabled").returns(true) do + @instance.service.put_bucket_versioning(@instance.key, 'Enabled') + @instance.versioning? + end + + tests("#versioning? false if suspended").returns(false) do + @instance.service.put_bucket_versioning(@instance.key, 'Suspended') + @instance.versioning? + end + end + + end + +end diff --git a/tests/models/storage/file_tests.rb b/tests/models/storage/file_tests.rb new file mode 100644 index 000000000..4e73c817b --- /dev/null +++ b/tests/models/storage/file_tests.rb @@ -0,0 +1,92 @@ +Shindo.tests("Storage[:aws] | file", ["aws"]) do + + require 'tempfile' + + file_attributes = { + :key => 'fog_file_tests', + :body => lorem_file, + :public => true + } + + directory_attributes = { + :key => uniq_id("fogfilestests") + } + + @directory = Fog::Storage[:aws].directories.create(directory_attributes) + + model_tests(@directory.files, file_attributes, Fog.mocking?) do + + tests("#version") do + tests("#version should be null if versioning isn't enabled").returns(nil) do + @instance.version + end + end + + end + + @directory.versioning = true + + model_tests(@directory.files, file_attributes, Fog.mocking?) do + + tests("#version") do + tests("#version should not be null if versioning is enabled").returns(false) do + @instance.version == nil + end + end + + @directory.files.create(:key => @instance.key) + @instance.destroy + + tests("#versions") do + tests('#versions.size includes versions (including DeleteMarkers) for all keys').returns(3) do + @instance.versions.size + end + + tests('#versions are all for the correct key').returns(true) do + # JRuby 1.7.5+ issue causes a SystemStackError: stack level too deep + # https://github.com/jruby/jruby/issues/1265 + pending if RUBY_PLATFORM == "java" and JRUBY_VERSION =~ /1\.7\.[5-8]/ + + @instance.versions.all? { |v| v.key == @instance.key } + end + end + + tests("#destroy") do + tests("#destroy a specific version should delete the version, not create a DeleteMarker").returns(2) do + @instance.destroy('versionId' => @instance.version) + @instance.versions.all.size + end + end + + tests("multipart upload") do + pending if Fog.mocking? + + # A 6MB file + @large_file = Tempfile.new("fog-test-aws-s3-multipart") + 6.times { @large_file.write("x" * (1024**2)) } + @large_file.rewind + + tests("#save(:multipart_chunk_size => 5242880)").succeeds do + @directory.files.create(:key => 'multipart-upload', :body => @large_file, :multipart_chunk_size => 5242880) + end + + @large_file.close + + end + + acl = Fog::Storage[:aws].get_object_acl(@directory.key, @instance.key).body["AccessControlList"] + + tests("#acl").returns(acl) do + @instance.acl + end + + tests("#public?").returns(acl.any? {|grant| grant['Grantee']['URI'] == 'http://acs.amazonaws.com/groups/global/AllUsers' && grant['Permission'] == 'READ'}) do + @instance.public? + end + + end + + @directory.versions.each(&:destroy) + @directory.destroy + +end diff --git a/tests/models/storage/files_tests.rb b/tests/models/storage/files_tests.rb new file mode 100644 index 000000000..b90dbd7b4 --- /dev/null +++ b/tests/models/storage/files_tests.rb @@ -0,0 +1,58 @@ +Shindo.tests("Storage[:aws] | files", ["aws"]) do + + file_attributes = { + :key => 'fog_file_tests', + :body => lorem_file, + :public => true + } + + directory_attributes = { + :key => uniq_id('fogfilestests') + } + + @directory = Fog::Storage[:aws].directories.create(directory_attributes) + @directory.versioning = true + + model_tests(@directory.files, file_attributes, Fog.mocking?) do + + v1 = @instance.version + v2 = @directory.service.put_object(@directory.key, @instance.key, 'version 2 content').headers['x-amz-version-id'] + v3 = @directory.service.delete_object(@directory.key, @instance.key).headers['x-amz-version-id'] + v4 = @directory.service.put_object(@directory.key, @instance.key, 'version 3 content').headers['x-amz-version-id'] + + tests("#get") do + tests("#get without version fetches the latest version").returns(v4) do + @directory.files.get(@instance.key).version + end + + tests("#get with version fetches that exact version").returns(v2) do + @directory.files.get(@instance.key, 'versionId' => v2).version + end + + tests("#get with a deleted version returns nil").returns(nil) do + pending # getting 405 Method Not Allowed + @directory.files.get(@instance.key, 'versionId' => v3) + end + end + + tests("#head") do + tests("#head without version fetches the latest version").returns(v4) do + @directory.files.head(@instance.key).version + end + + tests("#head with version fetches that exact version").returns(v2) do + @directory.files.head(@instance.key, 'versionId' => v2).version + end + + tests("#head with a deleted version returns nil").returns(nil) do + pending # getting 405 Method Not Allowed + @directory.files.head(@instance.key, 'versionId' => v3) + end + end + + end + + @directory.versions.each(&:destroy) + @directory.destroy + +end diff --git a/tests/models/storage/url_tests.rb b/tests/models/storage/url_tests.rb new file mode 100644 index 000000000..2a0628465 --- /dev/null +++ b/tests/models/storage/url_tests.rb @@ -0,0 +1,26 @@ +# encoding: utf-8 + +Shindo.tests('Aws | url', ["aws"]) do + + + @storage = Fog::Storage.new( + :provider => 'Aws', + :aws_access_key_id => '123', + :aws_secret_access_key => 'abc', + :region => 'us-east-1' + ) + + @file = @storage.directories.new(:key => 'fognonbucket').files.new(:key => 'test.txt') + + now = Fog::Time.now + if RUBY_VERSION > '1.8.7' # ruby 1.8.x doesn't provide hash ordering + tests('#url w/ response-cache-control').returns( + "https://fognonbucket.s3.amazonaws.com/test.txt?response-cache-control=No-cache&X-Amz-Expires=500&X-Amz-Date=#{now.to_iso8601_basic}&X-Amz-Algorithm=Aws4-HMAC-SHA256&X-Amz-Credential=123/#{now.utc.strftime('%Y%m%d')}/us-east-1/s3/aws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=" + ) do + + @file.url(Time.now + 500, :query => { 'response-cache-control' => 'No-cache' }).gsub(/(X-Amz-Signature=)[0-9a-f]+\z/,'\\1') + end + end + + +end diff --git a/tests/models/storage/version_tests.rb b/tests/models/storage/version_tests.rb new file mode 100644 index 000000000..cf21aba31 --- /dev/null +++ b/tests/models/storage/version_tests.rb @@ -0,0 +1,52 @@ +Shindo.tests("Storage[:aws] | version", ["aws"]) do + + file_attributes = { + :key => 'fog_file_tests', + :body => lorem_file, + :public => true + } + + directory_attributes = { + :key => uniq_id('fogfilestests') + } + + @directory = Fog::Storage[:aws].directories.create(directory_attributes) + @directory.versioning = true + + model_tests(@directory.files, file_attributes, Fog.mocking?) do + + @version_instance = @instance.versions.first + @directory.service.put_object(@directory.key, @instance.key, 'second version content') + + tests("#file") do + tests("#file should return the object associated with the version").returns(@version_instance.version) do + @version_instance.file.version + end + end + + tests("#delete_marker") do + tests("#delete_marker should be false if the version isn't a DeleteMarker'").returns(false) do + @version_instance.delete_marker + end + + tests("#delete_marker should be true if the version is a DeleteMarker'").returns(true) do + @instance.destroy + + @instance.versions.all.first.delete_marker + end + end + + tests("#destroy") do + tests("#destroy removes the specific version").returns(false) do + @version_instance.destroy + + @instance.versions.all.map(&:version).include?(@version_instance.version) + end + end + + end + + @directory.versions.each(&:destroy) + @directory.destroy + +end diff --git a/tests/models/storage/versions_tests.rb b/tests/models/storage/versions_tests.rb new file mode 100644 index 000000000..fa02fb351 --- /dev/null +++ b/tests/models/storage/versions_tests.rb @@ -0,0 +1,56 @@ +Shindo.tests("Storage[:aws] | versions", ["aws"]) do + + file_attributes = { + :key => 'fog_file_tests', + :body => lorem_file, + :public => true + } + + directory_attributes = { + :key => uniq_id('fogfilestests') + } + + model_tests(Fog::Storage[:aws].directories, directory_attributes, Fog.mocking?) do + @instance.versioning = true + + versions = [] + versions << @instance.service.put_object(@instance.key, 'one', 'abcde').headers['x-amz-version-id'] + + puts versions.first + + versions << @instance.service.put_object(@instance.key, 'one', '32423').headers['x-amz-version-id'] + versions << @instance.service.delete_object(@instance.key, 'one').headers['x-amz-version-id'] + versions.reverse! + + puts versions.first + + versions << @instance.service.put_object(@instance.key, 'two', 'aoeu').headers['x-amz-version-id'] + + tests('#versions') do + tests('#versions.size includes versions (including DeleteMarkers) for all keys').returns(4) do + @instance.versions.all.size + end + + tests('#versions returns the correct versions').returns(versions) do + @instance.versions.all.map(&:version) + end + end + + tests("#all") do + tests("#all for a directory returns all versions, regardless of key").returns(versions) do + @instance.versions.all.map(&:version) + end + + tests("#all for file returns only versions for that file").returns(1) do + @instance.files.get('two').versions.all.map(&:version).size + end + + tests("#all for file returns only versions for that file").returns(versions.last) do + @instance.files.get('two').versions.all.map(&:version).first + end + end + + @instance.versions.each(&:destroy) + end + +end diff --git a/tests/parsers/elb/describe_load_balancers.rb b/tests/parsers/elb/describe_load_balancers.rb new file mode 100644 index 000000000..8efcebe66 --- /dev/null +++ b/tests/parsers/elb/describe_load_balancers.rb @@ -0,0 +1,65 @@ +require 'fog/xml' +require 'fog/aws/parsers/elb/describe_load_balancers' + +DESCRIBE_LOAD_BALANCERS_RESULT = <<-EOF + + + + + + 2013-08-01T15:47:20.930Z + fog-test-elb + + 30 + TCP:80 + 10 + 5 + 2 + + + + + + HTTP + 80 + HTTP + 80 + + + + + + + + + + + us-east-1a + + fog-test-elb-1965660309.us-east-1.elb.amazonaws.com + Z3DZXE0Q79N41H + internet-facing + + amazon-elb + amazon-elb-sg + + fog-test-elb-1965660309.us-east-1.elb.amazonaws.com + + + + + + + a6ea2117-fac1-11e2-abd3-1740ab4ef14e + + +EOF + +Shindo.tests('Aws::ELB | parsers | describe_load_balancers', ['aws', 'elb', 'parser']) do + tests('parses the xml').formats(Aws::ELB::Formats::DESCRIBE_LOAD_BALANCERS) do + parser = Nokogiri::XML::SAX::Parser.new(Fog::Parsers::AWS::ELB::DescribeLoadBalancers.new) + parser.parse(DESCRIBE_LOAD_BALANCERS_RESULT) + parser.document.response + end +end diff --git a/tests/requests/auto_scaling/auto_scaling_tests.rb b/tests/requests/auto_scaling/auto_scaling_tests.rb new file mode 100644 index 000000000..e0a13a61b --- /dev/null +++ b/tests/requests/auto_scaling/auto_scaling_tests.rb @@ -0,0 +1,77 @@ +Shindo.tests('Aws::AutoScaling | auto_scaling_tests', ['aws', 'auto_scaling']) do + @asg_name = 'fog-test-asg' + @lc_name = 'fog-test-lc' + + tests('success') do + tests("#create_launch_configuration").formats(Aws::AutoScaling::Formats::BASIC) do + image_id = 'ami-8c1fece5' + instance_type = 't1.micro' + #listeners = [{'LoadBalancerPort' => 80, 'InstancePort' => 80, 'Protocol' => 'http'}] + Fog::AWS[:auto_scaling].create_launch_configuration(image_id, instance_type, @lc_name).body + end + + tests("#describe_launch_configurations").formats(Aws::AutoScaling::Formats::DESCRIBE_LAUNCH_CONFIGURATIONS) do + Fog::AWS[:auto_scaling].describe_launch_configurations().body + end + tests("#describe_launch_configurations").formats(Aws::AutoScaling::Formats::DESCRIBE_LAUNCH_CONFIGURATIONS) do + Fog::AWS[:auto_scaling].describe_launch_configurations('LaunchConfigurationNames' => @lc_name).body + end + tests("#describe_launch_configurations").formats(Aws::AutoScaling::Formats::DESCRIBE_LAUNCH_CONFIGURATIONS) do + Fog::AWS[:auto_scaling].describe_launch_configurations('LaunchConfigurationNames' => [@lc_name]).body + end + + tests("#create_auto_scaling_group").formats(Aws::AutoScaling::Formats::BASIC) do + zones = ['us-east-1d'] + max_size = 0 + min_size = 0 + Fog::AWS[:auto_scaling].create_auto_scaling_group(@asg_name, zones, @lc_name, max_size, min_size).body + end + + tests("#describe_auto_scaling_groups").formats(Aws::AutoScaling::Formats::DESCRIBE_AUTO_SCALING_GROUPS) do + Fog::AWS[:auto_scaling].describe_auto_scaling_groups().body + end + tests("#describe_auto_scaling_groups").formats(Aws::AutoScaling::Formats::DESCRIBE_AUTO_SCALING_GROUPS) do + Fog::AWS[:auto_scaling].describe_auto_scaling_groups('AutoScalingGroupNames' => @asg_name).body + end + tests("#describe_auto_scaling_groups").formats(Aws::AutoScaling::Formats::DESCRIBE_AUTO_SCALING_GROUPS) do + Fog::AWS[:auto_scaling].describe_auto_scaling_groups('AutoScalingGroupNames' => [@asg_name]).body + end + + tests("#describe_auto_scaling_instances").formats(Aws::AutoScaling::Formats::DESCRIBE_AUTO_SCALING_INSTANCES) do + Fog::AWS[:auto_scaling].describe_auto_scaling_instances().body + end + + tests("#describe_scaling_activities").formats(Aws::AutoScaling::Formats::DESCRIBE_SCALING_ACTIVITIES) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].describe_scaling_activities().body + end + tests("#describe_scaling_activities").formats(Aws::AutoScaling::Formats::DESCRIBE_SCALING_ACTIVITIES) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].describe_scaling_activities('ActivityIds' => '1').body + end + tests("#describe_scaling_activities").formats(Aws::AutoScaling::Formats::DESCRIBE_SCALING_ACTIVITIES) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].describe_scaling_activities('ActivityIds' => ['1', '2']).body + end + tests("#describe_scaling_activities").formats(Aws::AutoScaling::Formats::DESCRIBE_SCALING_ACTIVITIES) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].describe_scaling_activities('AutoScalingGroupName' => @asg_name).body + end + + tests("#set_desired_capacity").formats(Aws::AutoScaling::Formats::BASIC) do + desired_capacity = 0 + Fog::AWS[:auto_scaling].set_desired_capacity(@asg_name, desired_capacity).body + end + tests("#delete_auto_scaling_group").formats(Aws::AutoScaling::Formats::BASIC) do + Fog::AWS[:auto_scaling].delete_auto_scaling_group(@asg_name, 'ForceDelete' => true).body + end + + tests("#delete_auto_scaling_group that does not exists").raises(Fog::AWS::AutoScaling::ValidationError) do + Fog::AWS[:auto_scaling].delete_auto_scaling_group("group that does not exist") + end + + tests("#delete_launch_configuration").formats(Aws::AutoScaling::Formats::BASIC) do + Fog::AWS[:auto_scaling].delete_launch_configuration(@lc_name).body + end + end +end diff --git a/tests/requests/auto_scaling/describe_types_tests.rb b/tests/requests/auto_scaling/describe_types_tests.rb new file mode 100644 index 000000000..0986a6c14 --- /dev/null +++ b/tests/requests/auto_scaling/describe_types_tests.rb @@ -0,0 +1,102 @@ +Shindo.tests('Aws::AutoScaling | describe types requests', ['aws', 'auto_scaling']) do + + tests('success') do + + tests("#describe_adjustment_types").formats(Aws::AutoScaling::Formats::DESCRIBE_ADJUSTMENT_TYPES) do + body = Fog::AWS[:auto_scaling].describe_adjustment_types.body + + [ 'ChangeInCapacity', + 'ExactCapacity', + 'PercentChangeInCapacity' + ].each do |v| + returns(true, "AdjustmentTypes contains #{v}") do + body['DescribeAdjustmentTypesResult']['AdjustmentTypes'].any? {|t| t['AdjustmentType'] == v} + end + end + + body + end + + tests("#describe_auto_scaling_notification_types").formats(Aws::AutoScaling::Formats::DESCRIBE_AUTO_SCALING_NOTIFICATION_TYPES) do + body = Fog::AWS[:auto_scaling].describe_auto_scaling_notification_types.body + + [ 'autoscaling:EC2_INSTANCE_LAUNCH', + 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR', + 'autoscaling:EC2_INSTANCE_TERMINATE', + 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR', + 'autoscaling:TEST_NOTIFICATION' + ].each do |v| + returns(true, "AutoScalingNotificationTypes contains #{v}") do + body['DescribeAutoScalingNotificationTypesResult']['AutoScalingNotificationTypes'].include?(v) + end + end + + body + end + + tests("#describe_metric_collection_types").formats(Aws::AutoScaling::Formats::DESCRIBE_METRIC_COLLECTION_TYPES) do + body = Fog::AWS[:auto_scaling].describe_metric_collection_types.body + + [ 'GroupDesiredCapacity', + 'GroupInServiceInstances', + 'GroupMaxSize', + 'GroupMinSize', + 'GroupPendingInstances', + 'GroupTerminatingInstances', + 'GroupTotalInstances' + ].each do |v| + returns(true, "Metrics contains #{v}") do + body['DescribeMetricCollectionTypesResult']['Metrics'].any? {|t| t['Metric'] == v} + end + end + + [ '1Minute' + ].each do |v| + returns(true, "Granularities contains #{v}") do + body['DescribeMetricCollectionTypesResult']['Granularities'].any? {|t| t['Granularity'] == v} + end + end + + body + end + + tests("#describe_scaling_process_types").formats(Aws::AutoScaling::Formats::DESCRIBE_SCALING_PROCESS_TYPES) do + body = Fog::AWS[:auto_scaling].describe_scaling_process_types.body + + [ 'AZRebalance', + 'AddToLoadBalancer', + 'AlarmNotification', + 'HealthCheck', + 'Launch', + 'ReplaceUnhealthy', + 'ScheduledActions', + 'Terminate' + ].each do |v| + returns(true, "Processes contains #{v}") do + body['DescribeScalingProcessTypesResult']['Processes'].any? {|t| t['ProcessName'] == v} + end + end + + body + end + + tests("#describe_termination_policy_types").formats(Aws::AutoScaling::Formats::DESCRIBE_TERMINATION_POLICY_TYPES) do + body = Fog::AWS[:auto_scaling].describe_termination_policy_types.body + + [ 'ClosestToNextInstanceHour', + 'Default', + 'NewestInstance', + 'OldestInstance', + 'OldestLaunchConfiguration' + ].each do |v| + returns(true, "TerminationPolicyTypes contains #{v}") do + body['DescribeTerminationPolicyTypesResult']['TerminationPolicyTypes'].include?(v) + end + end + + body + end + + end + +end diff --git a/tests/requests/auto_scaling/helper.rb b/tests/requests/auto_scaling/helper.rb new file mode 100644 index 000000000..af66cf390 --- /dev/null +++ b/tests/requests/auto_scaling/helper.rb @@ -0,0 +1,228 @@ +class Aws + module AutoScaling + module Formats + BASIC = { + 'ResponseMetadata' => {'RequestId' => String} + } + + PAGINATED = { + 'NextToken' => Fog::Nullable::String + } + + ACTIVITY = { + 'ActivityId' => String, + 'AutoScalingGroupName' => String, + 'Cause' => Fog::Nullable::String, + 'Description' => String, + 'EndTime' => Time, + 'Progress' => Integer, + 'StartTime' => Time, + 'StatusCode' => String, + 'StatusMessage' => Fog::Nullable::String + } + + ALARM = { + 'AlarmARN' => String, + 'AlarmName' => String + } + + BLOCK_DEVICE_MAPPING = { + 'DeviceName' => String, + 'Ebs' => {'SnapshotId' => String, 'VolumeSize' => Integer}, + 'VirtualName' => String + } + + ENABLED_METRIC = { + 'Granularity' => Array, + 'Metric' => Array + } + + INSTANCE = { + 'AvailabilityZone' => String, + 'HealthStatus' => String, + 'InstanceId' => String, + 'LaunchConfigurationName' => String, + 'LifecycleState' => String + } + + NOTIFICATION_CONFIGURATION = { + 'AutoScalingGroupName' => String, + 'NotificationType' => String, + 'TopicARN' => String + } + + SCHEDULED_UPDATE_GROUP_ACTION = { + 'AutoScalingGroupName' => String, + 'DesiredCapacity' => Integer, + 'EndTime' => Time, + 'MaxSize' => Integer, + 'MinSize' => Integer, + 'Recurrence' => String, + 'ScheduledActionARN' => String, + 'ScheduledActionName' => String, + 'StartTime' => Time, + } + + PROCESS_TYPE = { + 'ProcessName' => String + } + + SUSPENDED_PROCESS = PROCESS_TYPE.merge({ + 'SuspensionReason' => String + }) + + TAG_DESCRIPTION = { + 'Key' => String, + 'PropagateAtLaunch' => Fog::Boolean, + 'ResourceId' => String, + 'ResourceType' => String, + 'Value' => Fog::Nullable::String + } + + AUTO_SCALING_GROUP = { + 'AutoScalingGroupARN' => String, + 'AutoScalingGroupName' => String, + 'AvailabilityZones' => Array, + 'CreatedTime' => Time, + 'DefaultCooldown' => Integer, + 'DesiredCapacity' => Integer, + 'EnabledMetrics' => [ENABLED_METRIC], + 'HealthCheckGracePeriod' => Integer, + 'HealthCheckType' => String, + 'Instances' => [INSTANCE], + 'LaunchConfigurationName' => String, + 'LoadBalancerNames' => Array, + 'MaxSize' => Integer, + 'MinSize' => Integer, + 'PlacementGroup' => Fog::Nullable::String, + 'Status' => Fog::Nullable::String, + 'SuspendedProcesses' => [SUSPENDED_PROCESS], + 'Tags' => [TAG_DESCRIPTION], + 'TerminationPolicies' => [String], + 'VPCZoneIdentifier' => Fog::Nullable::String + } + + AUTO_SCALING_INSTANCE_DETAILS = INSTANCE.merge({ + 'AutoScalingGroupName' => String + }) + + LAUNCH_CONFIGURATION = { + 'BlockDeviceMappings' => [BLOCK_DEVICE_MAPPING], + 'CreatedTime' => Time, + 'ImageId' => String, + 'InstanceMonitoring' => {'Enabled' => Fog::Boolean}, + 'InstanceType' => String, + 'KernelId' => Fog::Nullable::String, + 'KeyName' => Fog::Nullable::String, + 'LaunchConfigurationARN' => String, + 'LaunchConfigurationName' => String, + 'RamdiskId' => Fog::Nullable::String, + 'SpotPrice' => Fog::Nullable::String, + 'SecurityGroups' => Array, + 'UserData' => Fog::Nullable::String + } + + SCALING_POLICY = { + 'AdjustmentType' => String, + 'Alarms' => [ALARM], + 'AutoScalingGroupName' => String, + 'Cooldown' => Integer, + 'MinAdjustmentStep' => Integer, + 'PolicyARN' => String, + 'PolicyName' => String, + 'ScalingAdjustment' => Integer + } + + DESCRIBE_ADJUSTMENT_TYPES = BASIC.merge({ + 'DescribeAdjustmentTypesResult' => { + 'AdjustmentTypes' => [{'AdjustmentType' => String}] + } + }) + + DESCRIBE_AUTO_SCALING_GROUPS = BASIC.merge({ + 'DescribeAutoScalingGroupsResult' => PAGINATED.merge({ + 'AutoScalingGroups' => [AUTO_SCALING_GROUP], + }) + }) + + DESCRIBE_AUTO_SCALING_INSTANCES = BASIC.merge({ + 'DescribeAutoScalingInstancesResult' => PAGINATED.merge({ + 'AutoScalingInstances' => [AUTO_SCALING_INSTANCE_DETAILS], + }) + }) + + DESCRIBE_AUTO_SCALING_NOTIFICATION_TYPES = BASIC.merge({ + 'DescribeAutoScalingNotificationTypesResult' => { + 'AutoScalingNotificationTypes' => [String] + } + }) + + DESCRIBE_LAUNCH_CONFIGURATIONS = BASIC.merge({ + 'DescribeLaunchConfigurationsResult' => PAGINATED.merge({ + 'LaunchConfigurations' => [LAUNCH_CONFIGURATION], + }) + }) + + DESCRIBE_METRIC_COLLECTION_TYPES = BASIC.merge({ + 'DescribeMetricCollectionTypesResult' => { + 'Granularities' => [{'Granularity' => String}], + 'Metrics' => [{'Metric' => String}] + } + }) + + DESCRIBE_NOTIFICATION_CONFIGURATIONS = BASIC.merge({ + 'DescribeNotificationConfigurationsResult' => PAGINATED.merge({ + 'NotificationConfigurations' => [NOTIFICATION_CONFIGURATION] + }) + }) + + DESCRIBE_POLICIES = BASIC.merge({ + 'DescribePoliciesResult' => PAGINATED.merge({ + 'ScalingPolicies' => [SCALING_POLICY] + }) + }) + + DESCRIBE_SCALING_ACTIVITIES = BASIC.merge({ + 'DescribeScalingActivitiesResult' => PAGINATED.merge({ + 'Activities' => [ACTIVITY], + }) + }) + + DESCRIBE_SCALING_PROCESS_TYPES = BASIC.merge({ + 'DescribeScalingProcessTypesResult' => { + 'Processes' => [PROCESS_TYPE] + } + }) + + DESCRIBE_SCHEDULED_ACTIONS = BASIC.merge({ + 'DescribeScheduledActionsResult' => PAGINATED.merge({ + 'ScheduledUpdateGroupActions' => [SCHEDULED_UPDATE_GROUP_ACTION] + }) + }) + + DESCRIBE_TAGS = BASIC.merge({ + 'DescribeTagsResult' => PAGINATED.merge({ + 'Tags' => [TAG_DESCRIPTION] + }) + }) + + DESCRIBE_TERMINATION_POLICY_TYPES = BASIC.merge({ + 'DescribeTerminationPolicyTypesResult' => { + 'TerminationPolicyTypes' => [String] + } + }) + + PUT_SCALING_POLICY = BASIC.merge({ + 'PutScalingPolicyResult' => { + 'PolicyARN' => String + } + }) + + TERMINATE_INSTANCE_IN_AUTO_SCALING_GROUP = BASIC.merge({ + 'TerminateInstanceInAutoScalingGroupResult' => { + 'Activity' => [ACTIVITY] + } + }) + end + end +end diff --git a/tests/requests/auto_scaling/model_tests.rb b/tests/requests/auto_scaling/model_tests.rb new file mode 100644 index 000000000..1c5cbdc72 --- /dev/null +++ b/tests/requests/auto_scaling/model_tests.rb @@ -0,0 +1,233 @@ +Shindo.tests('Aws::AutoScaling | model_tests', ['aws', 'auto_scaling']) do + + tests('success') do + lc = nil + lc_id = 'fog-model-lc' + + tests('configurations') do + tests('getting a missing configuration') do + returns(nil) { Fog::AWS[:auto_scaling].configurations.get('fog-no-such-lc') } + end + + tests('create configuration') do + lc = Fog::AWS[:auto_scaling].configurations.create(:id => lc_id, :image_id => 'ami-8c1fece5', :instance_type => 't1.micro') + #tests("dns names is set").returns(true) { lc.dns_name.is_a?(String) } + tests("created_at is set").returns(true) { Time === lc.created_at } + #tests("policies is empty").returns([]) { lc.policies } + end + + tests('all configurations') do + lc_ids = Fog::AWS[:auto_scaling].configurations.all.map{|e| e.id} + tests("contains lc").returns(true) { lc_ids.include? lc_id } + end + + tests('get configuration') do + lc2 = Fog::AWS[:auto_scaling].configurations.get(lc_id) + tests('ids match').returns(lc_id) { lc2.id } + end + + tests('creating a duplicate configuration') do + raises(Fog::AWS::AutoScaling::IdentifierTaken) do + Fog::AWS[:auto_scaling].configurations.create(:id => lc_id, :image_id => 'ami-8c1fece5', :instance_type => 't1.micro') + end + end + end + + tests('groups') do + tests('getting a missing group') do + returns(nil) { Fog::AWS[:auto_scaling].groups.get('fog-no-such-asg') } + end + + asg = nil + asg_id = 'fog-model-asg' + + tests('create') do + asg = Fog::AWS[:auto_scaling].groups.create(:id => asg_id, :availability_zones => ['us-east-1d'], :launch_configuration_name => lc_id) + #tests("dns names is set").returns(true) { asg.dns_name.is_a?(String) } + tests("created_at is set").returns(true) { Time === asg.created_at } + #tests("policies is empty").returns([]) { asg.policies } + end + + tests('all') do + asg_ids = Fog::AWS[:auto_scaling].groups.all.map{|e| e.id} + tests("contains asg").returns(true) { asg_ids.include? asg_id } + end + + tests('get') do + asg2 = Fog::AWS[:auto_scaling].groups.get(asg_id) + tests('ids match').returns(asg_id) { asg2.id } + end + + tests('suspend processes') do + asg.suspend_processes() + tests('processes suspended').returns([]) { asg.suspended_processes } + end + + tests('resume processes') do + asg.resume_processes() + tests('no processes suspended').returns([]) { asg.suspended_processes } + end + + tests('creating a duplicate group') do + raises(Fog::AWS::AutoScaling::IdentifierTaken) do + Fog::AWS[:auto_scaling].groups.create(:id => asg_id, :availability_zones => ['us-east-1d'], :launch_configuration_name => lc_id) + end + end + + tests('destroy group') do + asg.destroy + asg = nil + end + + #tests('registering an invalid instance') do + # raises(Fog::AWS::AutoScaling::InvalidInstance) { asg.register_instances('i-00000000') } + #end + + #tests('deregistering an invalid instance') do + # raises(Fog::AWS::AutoScaling::InvalidInstance) { asg.deregister_instances('i-00000000') } + #end + end + + tests('configurations') do + tests('destroy configuration') do + lc.destroy + lc = nil + end + end + + #server = Fog::AWS[:compute].servers.create + #tests('register instance') do + # begin + # elb.register_instances(server.id) + # rescue Fog::AWS::ELB::InvalidInstance + # # It may take a moment for a newly created instances to be visible to ELB requests + # raise if @retried_registered_instance + # @retried_registered_instance = true + # sleep 1 + # retry + # end + # + # returns([server.id]) { elb.instances } + #end + + #tests('instance_health') do + # returns('OutOfService') do + # elb.instance_health.detect{|hash| hash['InstanceId'] == server.id}['State'] + # end + # + # returns([server.id]) { elb.instances_out_of_service } + #end + + #tests('deregister instance') do + # elb.deregister_instances(server.id) + # returns([]) { elb.instances } + #end + #server.destroy + + #tests('disable_availability_zones') do + # elb.disable_availability_zones(%w{us-east-1c us-east-1d}) + # returns(%w{us-east-1a us-east-1b}) { elb.availability_zones.sort } + #end + + #tests('enable_availability_zones') do + # elb.enable_availability_zones(%w{us-east-1c us-east-1d}) + # returns(%w{us-east-1a us-east-1b us-east-1c us-east-1d}) { elb.availability_zones.sort } + #end + + #tests('default health check') do + # default_health_check = { + # "HealthyThreshold"=>10, + # "Timeout"=>5, + # "UnhealthyThreshold"=>2, + # "Interval"=>30, + # "Target"=>"TCP:80" + # } + # returns(default_health_check) { elb.health_check } + #end + + #tests('configure_health_check') do + # new_health_check = { + # "HealthyThreshold"=>5, + # "Timeout"=>10, + # "UnhealthyThreshold"=>3, + # "Interval"=>15, + # "Target"=>"HTTP:80/index.html" + # } + # elb.configure_health_check(new_health_check) + # returns(new_health_check) { elb.health_check } + #end + + #tests('listeners') do + # default_listener_description = [{"Listener"=>{"InstancePort"=>80, "Protocol"=>"HTTP", "LoadBalancerPort"=>80}, "PolicyNames"=>[]}] + # tests('default') do + # returns(1) { elb.listeners.size } + # + # listener = elb.listeners.first + # returns([80,80,'HTTP', []]) { [listener.instance_port, listener.lb_port, listener.protocol, listener.policy_names] } + # + # end + # + # tests('#get') do + # returns(80) { elb.listeners.get(80).lb_port } + # end + # + # tests('create') do + # new_listener = { 'InstancePort' => 443, 'LoadBalancerPort' => 443, 'Protocol' => 'TCP'} + # elb.listeners.create(:instance_port => 443, :lb_port => 443, :protocol => 'TCP') + # returns(2) { elb.listeners.size } + # returns(443) { elb.listeners.get(443).lb_port } + # end + # + # tests('destroy') do + # elb.listeners.get(443).destroy + # returns(nil) { elb.listeners.get(443) } + # end + #end + + #tests('policies') do + # app_policy_id = 'my-app-policy' + # + # tests 'are empty' do + # returns([]) { elb.policies.to_a } + # end + # + # tests('#all') do + # returns([]) { elb.policies.all.to_a } + # end + # + # tests('create app policy') do + # elb.policies.create(:id => app_policy_id, :cookie => 'my-app-cookie', :cookie_stickiness => :app) + # returns(app_policy_id) { elb.policies.first.id } + # end + # + # tests('get policy') do + # returns(app_policy_id) { elb.policies.get(app_policy_id).id } + # end + # + # tests('destroy app policy') do + # elb.policies.first.destroy + # returns([]) { elb.policies.to_a } + # end + # + # lb_policy_id = 'my-lb-policy' + # tests('create lb policy') do + # elb.policies.create(:id => lb_policy_id, :expiration => 600, :cookie_stickiness => :lb) + # returns(lb_policy_id) { elb.policies.first.id } + # end + # + # tests('setting a listener policy') do + # elb.set_listener_policy(80, lb_policy_id) + # returns([lb_policy_id]) { elb.listeners.get(80).policy_names } + # end + # + # tests('unsetting a listener policy') do + # elb.unset_listener_policy(80) + # returns([]) { elb.listeners.get(80).policy_names } + # end + # + # tests('a malformed policy') do + # raises(ArgumentError) { elb.policies.create(:id => 'foo', :cookie_stickiness => 'invalid stickiness') } + # end + #end + end +end diff --git a/tests/requests/auto_scaling/notification_configuration_tests.rb b/tests/requests/auto_scaling/notification_configuration_tests.rb new file mode 100644 index 000000000..0ec6fa5e8 --- /dev/null +++ b/tests/requests/auto_scaling/notification_configuration_tests.rb @@ -0,0 +1,124 @@ +Shindo.tests('Aws::AutoScaling | notification configuration requests', ['aws', 'auto_scaling']) do + + image_id = { # Ubuntu 12.04 LTS 64-bit EBS + 'ap-northeast-1' => 'ami-60c77761', + 'ap-southeast-1' => 'ami-a4ca8df6', + 'ap-southeast-2' => 'ami-fb8611c1', + 'eu-west-1' => 'ami-e1e8d395', + 'sa-east-1' => 'ami-8cd80691', + 'us-east-1' => 'ami-a29943cb', + 'us-west-1' => 'ami-87712ac2', + 'us-west-2' => 'ami-20800c10' + } + + now = Time.now.utc.to_i + lc_name = "fog-test-#{now}" + asg_name = "fog-test-#{now}" + + topic_name = "fog-test-#{now}" + begin + topic = Fog::AWS[:sns].create_topic(topic_name).body + topic_arn = topic['TopicArn'] + rescue Fog::Errors::MockNotImplemented + topic_arn = Fog::AWS::Mock.arn('sns', Fog::AWS[:auto_scaling].data[:owner_id], "fog-test-#{now}", Fog::AWS[:auto_scaling].region) + end + + lc = Fog::AWS[:auto_scaling].create_launch_configuration(image_id[Fog::AWS[:auto_scaling].region], 't1.micro', lc_name) + asg = Fog::AWS[:auto_scaling].create_auto_scaling_group(asg_name, "#{Fog::AWS[:auto_scaling].region}a", lc_name, 0, 0) + + tests('raises') do + tests("#put_notification_configuration(non-existent-group)").raises(Fog::AWS::AutoScaling::ValidationError) do + Fog::AWS[:auto_scaling].put_notification_configuration('fog-test-nonexistent-group', 'autoscaling:TEST_NOTIFICATION', topic_arn) + end + + tests("#put_notification_configuration(null-types)").raises(Fog::AWS::AutoScaling::ValidationError) do + Fog::AWS[:auto_scaling].put_notification_configuration(asg_name, [], topic_arn) + end + end + + tests('success') do + tests("#put_notification_configuration(string)").formats(Aws::AutoScaling::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].put_notification_configuration(asg_name, 'autoscaling:TEST_NOTIFICATION', topic_arn).body + end + + tests("#describe_notification_configurations").formats(Aws::AutoScaling::Formats::DESCRIBE_NOTIFICATION_CONFIGURATIONS) do + pending if Fog.mocking? + body = Fog::AWS[:auto_scaling].describe_notification_configurations('AutoScalingGroupNames' => asg_name).body + notification_configurations = body['DescribeNotificationConfigurationsResult']['NotificationConfigurations'] + returns(true, 'exactly 1 configurations') do + notification_configurations.size == 1 + end + returns(true) do + config = notification_configurations.first + config['AutoScalingGroupName'] == asg_name && config['TopicARN'] == topic_arn && config['NotificationType'] == 'autoscaling:TEST_NOTIFICATION' + end + body + end + + tests("#put_notification_configuration(array)").formats(Aws::AutoScaling::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].put_notification_configuration(asg_name, ['autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_TERMINATE'], topic_arn).body + end + + tests("#describe_notification_configurations").formats(Aws::AutoScaling::Formats::DESCRIBE_NOTIFICATION_CONFIGURATIONS) do + pending if Fog.mocking? + body = Fog::AWS[:auto_scaling].describe_notification_configurations('AutoScalingGroupName' => asg_name).body + notification_configurations = body['DescribeNotificationConfigurationsResult']['NotificationConfigurations'] + returns(true, 'exactly 2 configurations') do + notification_configurations.size == 2 + end + [ 'autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_TERMINATE'].each do |type| + returns(true) do + notification_configurations.any? do |config| + config['AutoScalingGroupName'] == asg_name && config['TopicARN'] == topic_arn && config['NotificationType'] == type + end + end + end + body + end + + tests("#describe_notification_configurations(all)").formats(Aws::AutoScaling::Formats::DESCRIBE_NOTIFICATION_CONFIGURATIONS) do + pending if Fog.mocking? + body = Fog::AWS[:auto_scaling].describe_notification_configurations().body + notification_configurations = body['DescribeNotificationConfigurationsResult']['NotificationConfigurations'] + returns(true, 'at least 2 configurations') do + notification_configurations.size >= 2 + end + [ 'autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_TERMINATE'].each do |type| + returns(true) do + notification_configurations.any? do |config| + config['AutoScalingGroupName'] == asg_name && config['TopicARN'] == topic_arn && config['NotificationType'] == type + end + end + end + + body + end + + tests("#delete_notification_configuration").formats(Aws::AutoScaling::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:auto_scaling].delete_notification_configuration(asg_name, topic_arn).body + end + + tests("#describe_notification_configurations").formats(Aws::AutoScaling::Formats::DESCRIBE_NOTIFICATION_CONFIGURATIONS) do + pending if Fog.mocking? + body = Fog::AWS[:auto_scaling].describe_notification_configurations('AutoScalingGroupNames' => asg_name).body + returns(true) do + body['DescribeNotificationConfigurationsResult']['NotificationConfigurations'].empty? + end + body + end + end + + Fog::AWS[:auto_scaling].delete_auto_scaling_group(asg_name) + Fog::AWS[:auto_scaling].delete_launch_configuration(lc_name) + + if topic + begin + Fog::AWS[:sns].delete_topic(topic_arn) + rescue Fog::Errors::MockNotImplemented + end + end + +end diff --git a/tests/requests/auto_scaling/tag_tests.rb b/tests/requests/auto_scaling/tag_tests.rb new file mode 100644 index 000000000..c84777372 --- /dev/null +++ b/tests/requests/auto_scaling/tag_tests.rb @@ -0,0 +1,63 @@ +Shindo.tests('Aws::AutoScaling | tag requests', ['aws', 'auto_scaling']) do + + image_id = { # Ubuntu 12.04 LTS 64-bit EBS + 'ap-northeast-1' => 'ami-60c77761', + 'ap-southeast-1' => 'ami-a4ca8df6', + 'ap-southeast-2' => 'ami-fb8611c1', + 'eu-west-1' => 'ami-e1e8d395', + 'sa-east-1' => 'ami-8cd80691', + 'us-east-1' => 'ami-a29943cb', + 'us-west-1' => 'ami-87712ac2', + 'us-west-2' => 'ami-20800c10' + } + + now = Time.now.utc.to_i + lc_name = "fog-test-#{now}" + asg_name = "fog-test-#{now}" + + asg_tag = { + 'Key' => 'Name', + 'PropagateAtLaunch' => true, + 'ResourceId' => asg_name, + 'ResourceType' => 'auto-scaling-group', + 'Value' => asg_name + } + + lc = Fog::AWS[:auto_scaling].create_launch_configuration(image_id[Fog::AWS[:auto_scaling].region], 't1.micro', lc_name) + asg = Fog::AWS[:auto_scaling].create_auto_scaling_group(asg_name, "#{Fog::AWS[:auto_scaling].region}a", lc_name, 0, 0, 'Tags' => [asg_tag]) + + tests('raises') do + tests("#create_or_update_tags(empty)").raises(Fog::AWS::AutoScaling::ValidationError) do + Fog::AWS[:auto_scaling].create_or_update_tags([]) + end + + tests("#delete_tags(empty)").raises(Fog::AWS::AutoScaling::ValidationError) do + Fog::AWS[:auto_scaling].delete_tags([]) + end + end + + tests('success') do + tests("#describe_auto_scaling_groups(#{asg_name}").formats(Aws::AutoScaling::Formats::DESCRIBE_AUTO_SCALING_GROUPS) do + body = Fog::AWS[:auto_scaling].describe_auto_scaling_groups('AutoScalingGroupNames' => asg_name).body + auto_scaling_group = body['DescribeAutoScalingGroupsResult']['AutoScalingGroups'].first + returns(true) { auto_scaling_group.key?('Tags') } + returns(true) { auto_scaling_group['Tags'].size == 1 } + returns(true) { auto_scaling_group['Tags'].first == asg_tag } + body + end + + tests("#describe_tags").formats(Aws::AutoScaling::Formats::DESCRIBE_TAGS) do + pending if Fog.mocking? + body = Fog::AWS[:auto_scaling].describe_tags.body + tags = body['DescribeTagsResult']['Tags'] + returns(true) { tags.any? {|tag| tag == asg_tag} } + body + end + + # TODO: more tests! + end + + Fog::AWS[:auto_scaling].delete_auto_scaling_group(asg_name) + Fog::AWS[:auto_scaling].delete_launch_configuration(lc_name) + +end diff --git a/tests/requests/beanstalk/application_tests.rb b/tests/requests/beanstalk/application_tests.rb new file mode 100644 index 000000000..cf1e4929f --- /dev/null +++ b/tests/requests/beanstalk/application_tests.rb @@ -0,0 +1,140 @@ +Shindo.tests('Aws::ElasticBeanstalk | application_tests', ['aws', 'beanstalk']) do + + def unique_name(prefix) + #get time (with 1/100th of sec accuracy) + #want unique domain name and if provider is fast, this can be called more than once per second + time = Time.now.to_i.to_s + prefix + time + end + + unless Fog.mocking? + @beanstalk = Fog::AWS[:beanstalk] + end + + @test_description = "A unique description." + + @test_app_name = unique_name("fog-test-app-") + + tests('success') do + pending if Fog.mocking? + + @describe_applications_format = { + 'DescribeApplicationsResult' => { + 'Applications' => [ + 'ApplicationName' => String, + 'ConfigurationTemplates' => [String], + 'Description' => Fog::Nullable::String, + 'DateCreated' => Time, + 'DateUpdated' => Time, + 'Versions' => [String] + ]}, + 'ResponseMetadata' => {'RequestId'=> String}, + } + + tests("#describe_applications format").formats(@describe_applications_format) do + result = @beanstalk.describe_applications.body + end + + test("#create_application") { + response = @beanstalk.create_application({ + 'ApplicationName' => @test_app_name, + 'Description' => @test_description + }) + + result = false + if response.status == 200 + + app_info = response.body['CreateApplicationResult']['Application'] + if app_info + if app_info['ApplicationName'] == @test_app_name && + app_info['Description'] == @test_description && + app_info['ConfigurationTemplates'].empty? && + app_info['Versions'].empty? + result = true + end + end + end + + result + } + + test("#describe_applications all") { + response = @beanstalk.describe_applications + + result = false + if response.status == 200 + apps = response.body['DescribeApplicationsResult']['Applications'] + apps.each { |app_info| + if app_info + if app_info['ApplicationName'] == @test_app_name && + app_info['Description'] == @test_description && + app_info['ConfigurationTemplates'].empty? && + app_info['Versions'].empty? + result = true + end + end + } + end + + result + } + + test("#create_application filter") { + # Test for a specific app + response = @beanstalk.describe_applications([@test_app_name]) + + result = false + if response.status == 200 + apps = response.body['DescribeApplicationsResult']['Applications'] + if apps && apps.length == 1 + app_info = apps.first + if app_info['ApplicationName'] == @test_app_name && + app_info['Description'] == @test_description && + app_info['ConfigurationTemplates'].empty? && + app_info['Versions'].empty? + result = true + end + end + end + + result + } + + test("#update_application description") { + + @test_description = "A completely new description." + + response = @beanstalk.update_application({ + 'ApplicationName' => @test_app_name, + 'Description' => @test_description + }) + + result = false + if response.status == 200 + app_info = response.body['UpdateApplicationResult']['Application'] + if app_info + if app_info['ApplicationName'] == @test_app_name && + app_info['Description'] == @test_description && + app_info['ConfigurationTemplates'].empty? && + app_info['Versions'].empty? + result = true + end + end + end + + result + } + + test("#delete_application") { + response = @beanstalk.delete_application(@test_app_name) + + result = false + if response.status == 200 + result = true + end + + result + } + + end +end diff --git a/tests/requests/beanstalk/solution_stack_tests.rb b/tests/requests/beanstalk/solution_stack_tests.rb new file mode 100644 index 000000000..27375e469 --- /dev/null +++ b/tests/requests/beanstalk/solution_stack_tests.rb @@ -0,0 +1,22 @@ +Shindo.tests('Aws::ElasticBeanstalk | solution_stack_tests', ['aws', 'beanstalk']) do + + tests('success') do + pending if Fog.mocking? + + @solution_stack_result_format = { + 'ListAvailableSolutionStacksResult' => { + 'SolutionStackDetails' => [ + 'SolutionStackName' => String, + 'PermittedFileTypes' => [String] + ], + 'SolutionStacks' => [String] + }, + 'ResponseMetadata' => {'RequestId'=> String}, + } + tests("#list_available_solution_stacks").formats(@solution_stack_result_format) do + Fog::AWS[:beanstalk].list_available_solution_stacks.body + + end + + end +end diff --git a/tests/requests/cdn/cdn_tests.rb b/tests/requests/cdn/cdn_tests.rb new file mode 100644 index 000000000..708f4c637 --- /dev/null +++ b/tests/requests/cdn/cdn_tests.rb @@ -0,0 +1,252 @@ +Shindo.tests('Fog::CDN[:aws] | CDN requests', ['aws', 'cdn']) do + + @cf_connection = Fog::CDN[:aws] + + tests('distributions success') do + + test('get current ditribution list count') do + + @count= 0 + response = @cf_connection.get_distribution_list + if response.status == 200 + @distributions = response.body['DistributionSummary'] + @count = @distributions.count + end + + response.status == 200 + end + + test('create distribution') { + + result = false + + response = @cf_connection.post_distribution('S3Origin' => { 'DNSName' => 'test_cdn.s3.amazonaws.com'}, 'Enabled' => true) + if response.status == 201 + @dist_id = response.body['Id'] + @etag = response.headers['ETag'] + @caller_reference = response.body['DistributionConfig']['CallerReference'] + if (@dist_id.length > 0) + result = true + end + end + + result + } + + test("get info on distribution #{@dist_id}") { + + result = false + + response = @cf_connection.get_distribution(@dist_id) + if response.status == 200 + @etag = response.headers['ETag'] + status = response.body['Status'] + if ((status == 'Deployed') or (status == 'InProgress')) and not @etag.nil? + result = true + end + end + + result + } + + test('list distributions') do + + result = false + + response = @cf_connection.get_distribution_list + if response.status == 200 + distributions = response.body['DistributionSummary'] + if (distributions.count > 0) + dist = distributions[0] + dist_id = dist['Id'] + end + max_items = response.body['MaxItems'] + + if (dist_id.length > 0) and (max_items > 0) + result = true + end + + end + + result + end + + test("invalidate paths") { + + response = @cf_connection.post_invalidation(@dist_id, ["/test.html", "/path/to/file.html"]) + if response.status == 201 + @invalidation_id = response.body['Id'] + end + + response.status == 201 + } + + test("list invalidations") { + + result = false + + response = @cf_connection.get_invalidation_list(@dist_id) + if response.status == 200 + if response.body['InvalidationSummary'].find { |f| f['Id'] == @invalidation_id } + result = true + end + end + + result + } + + test("get invalidation information") { + + result = false + + response = @cf_connection.get_invalidation(@dist_id, @invalidation_id) + if response.status == 200 + paths = response.body['InvalidationBatch']['Path'].sort + status = response.body['Status'] + if status.length > 0 and paths == [ '/test.html', '/path/to/file.html' ].sort + result = true + end + end + + result + } + + test("disable distribution #{@dist_id} - can take 15 minutes to complete...") { + + result = false + + response = @cf_connection.put_distribution_config(@dist_id, @etag, 'S3Origin' => { 'DNSName' => 'test_cdn.s3.amazonaws.com'}, 'Enabled' => false, 'CallerReference' => @caller_reference) + if response.status == 200 + @etag = response.headers['ETag'] + unless @etag.nil? + result = true + end + end + + result + } + + test("remove distribution #{@dist_id}") { + + result = true + + # unfortunately you can delete only after a distribution becomes Deployed + Fog.wait_for { + response = @cf_connection.get_distribution(@dist_id) + @etag = response.headers['ETag'] + response.status == 200 and response.body['Status'] == 'Deployed' + } + + response = @cf_connection.delete_distribution(@dist_id, @etag) + if response.status != 204 + result = false + end + + result + } + end + + tests('streaming distributions success') do + + test('get current streaming ditribution list count') do + + @count= 0 + response = @cf_connection.get_streaming_distribution_list + if response.status == 200 + @distributions = response.body['StreamingDistributionSummary'] + @count = @distributions.count + end + + response.status == 200 + end + + test('create distribution') { + + result = false + + response = @cf_connection.post_streaming_distribution('S3Origin' => { 'DNSName' => 'test_cdn.s3.amazonaws.com'}, 'Enabled' => true) + if response.status == 201 + @dist_id = response.body['Id'] + @etag = response.headers['ETag'] + @caller_reference = response.body['StreamingDistributionConfig']['CallerReference'] + if (@dist_id.length > 0) + result = true + end + end + + result + } + + test("get info on distribution #{@dist_id}") { + + result = false + + response = @cf_connection.get_streaming_distribution(@dist_id) + if response.status == 200 + @etag = response.headers['ETag'] + status = response.body['Status'] + if ((status == 'Deployed') or (status == 'InProgress')) and not @etag.nil? + result = true + end + end + + result + } + + test('list streaming distributions') do + + result = false + + response = @cf_connection.get_streaming_distribution_list + if response.status == 200 + distributions = response.body['StreamingDistributionSummary'] + if (distributions.count > 0) + dist = distributions[0] + dist_id = dist['Id'] + end + max_items = response.body['MaxItems'] + + if (dist_id.length > 0) and (max_items > 0) + result = true + end + + end + + result + end + + test("disable distribution #{@dist_id} - can take 15 minutes to complete...") { + + result = false + + response = @cf_connection.put_streaming_distribution_config(@dist_id, @etag, 'S3Origin' => { 'DNSName' => 'test_cdn.s3.amazonaws.com'}, 'Enabled' => false, 'CallerReference' => @caller_reference) + if response.status == 200 + @etag = response.headers['ETag'] + unless @etag.nil? + result = true + end + end + + result + } + + test("remove distribution #{@dist_id}") { + + result = true + + # unfortunately you can delete only after a distribution becomes Deployed + Fog.wait_for { + response = @cf_connection.get_streaming_distribution(@dist_id) + @etag = response.headers['ETag'] + response.status == 200 and response.body['Status'] == 'Deployed' + } + + response = @cf_connection.delete_streaming_distribution(@dist_id, @etag) + if response.status != 204 + result = false + end + + result + } + end +end diff --git a/tests/requests/cloud_formation/stack_tests.rb b/tests/requests/cloud_formation/stack_tests.rb new file mode 100644 index 000000000..f49085e4a --- /dev/null +++ b/tests/requests/cloud_formation/stack_tests.rb @@ -0,0 +1,167 @@ +Shindo.tests('Aws::CloudFormation | stack requests', ['aws', 'cloudformation']) do + + @validate_template_format = { + 'Description' => String, + 'Parameters' => [ + { + 'DefaultValue' => Fog::Nullable::String, + 'Description' => String, + 'NoEcho' => Fog::Boolean, + 'ParameterKey' => String, + } + ], + 'RequestId' => String + } + + @create_stack_format = { + 'RequestId' => String, + 'StackId' => String + } + + @update_stack_format = { + 'RequestId' => String, + 'StackId' => String + } + + @get_template_format = { + 'RequestId' => String, + 'TemplateBody' => String + } + + @describe_stacks_format = { + 'RequestId' => String, + 'Stacks' => [ + { + 'CreationTime' => Time, + 'DisableRollback' => Fog::Boolean, + 'Outputs' => [ + { + 'OutputKey' => String, + 'OutputValue' => String + } + ], + 'Parameters' => [ + { + 'ParameterKey' => String, + 'ParameterValue' => String, + } + ], + 'StackId' => String, + 'StackName' => String, + 'StackStatus' => String, + } + ] + } + + @describe_stack_events_format = { + 'RequestId' => String, + 'StackEvents' => [ + { + 'EventId' => String, + 'LogicalResourceId' => String, + 'PhysicalResourceId' => String, + 'ResourceProperties' => String, + 'ResourceStatus' => String, + 'ResourceStatusReason' => Fog::Nullable::String, + 'ResourceType' => String, + 'StackId' => String, + 'StackName' => String, + 'Timestamp' => Time + } + ] + } + + @describe_stack_resources_format = { + 'RequestId' => String, + 'StackResources' => [ + { + 'LogicalResourceId' => String, + 'PhysicalResourceId' => String, + 'ResourceStatus' => String, + 'ResourceType' => String, + 'StackId' => String, + 'StackName' => String, + 'Timestamp' => Time + } + ] + } + + tests('success') do + + unless Fog.mocking? + @stack_name = 'fogstack' << Time.now.to_i.to_s + @keypair = Fog::Compute[:aws].key_pairs.create(:name => 'cloudformation') + @template_url = 'https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2InstanceSample-1.0.0.template' + end + + tests("validate_template('TemplateURL' => '#{@template_url}')").formats(@validate_template_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].validate_template('TemplateURL' => @template_url).body + end + + tests("create_stack('#{@stack_name}', 'TemplateURL' => '#{@template_url}', Parameters => {'KeyName' => 'cloudformation'})").formats(@create_stack_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].create_stack( + @stack_name, + 'TemplateURL' => @template_url, + 'Parameters' => {'KeyName' => 'cloudformation'} + ).body + end + + tests("update_stack('#{@stack_name}', 'TemplateURL' => '#{@template_url}', Parameters => {'KeyName' => 'cloudformation'})").formats(@update_stack_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].update_stack( + @stack_name, + 'TemplateURL' => @template_url, + 'Parameters' => {'KeyName' => 'cloudformation'} + ).body + end + + tests("get_template('#{@stack_name})").formats(@get_template_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].get_template(@stack_name).body + end + + tests("describe_stacks").formats(@describe_stacks_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].describe_stacks.body + end + + sleep(1) # avoid throttling + + tests("describe_stack_events('#{@stack_name}')").formats(@describe_stack_events_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].describe_stack_events(@stack_name).body + end + + tests("describe_stack_resources('StackName' => '#{@stack_name}')").formats(@describe_stack_resources_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].describe_stack_resources('StackName' => @stack_name).body + end + + tests("delete_stack('#{@stack_name}')").succeeds do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].delete_stack(@stack_name) + end + + tests("list_stacks").succeeds do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].list_stacks.body + end + + tests("list_stack_resources").succeeds do + pending if Fog.mocking? + Fog::AWS[:cloud_formation].list_stack_resources("StackName"=>@stack_name).body + end + + unless Fog.mocking? + @keypair.destroy + end + + end + + tests('failure') do + + end + +end diff --git a/tests/requests/cloud_watch/get_metric_statistics_tests.rb b/tests/requests/cloud_watch/get_metric_statistics_tests.rb new file mode 100644 index 000000000..2246aa59a --- /dev/null +++ b/tests/requests/cloud_watch/get_metric_statistics_tests.rb @@ -0,0 +1,28 @@ +Shindo.tests('Aws::CloudWatch | metric requests', ['aws', 'cloudwatch']) do + tests('success') do + + @metrics_statistic_format = { + 'GetMetricStatisticsResult' => { + 'Label' => String, + 'Datapoints' => [{ + "Timestamp" => Time, + 'Unit' => String, + 'Minimum' => Float, + 'Maximum' => Float, + 'Average' => Float, + 'Sum' => Float, + 'SampleCount' => Float + }], + }, + 'ResponseMetadata' => { + 'RequestId' => String + } + } + + tests("#get_metric_statistics").formats(@metrics_statistic_format) do + pending if Fog.mocking? + instanceId = 'i-420c352f' + Fog::AWS[:cloud_watch].get_metric_statistics({'Statistics' => ['Minimum','Maximum','Sum','SampleCount','Average'], 'StartTime' => (Time.now-600).iso8601, 'EndTime' => Time.now.iso8601, 'Period' => 60, 'MetricName' => 'DiskReadBytes', 'Namespace' => 'Aws/EC2', 'Dimensions' => [{'Name' => 'InstanceId', 'Value' => instanceId}]}).body + end + end +end diff --git a/tests/requests/cloud_watch/list_metrics_test.rb b/tests/requests/cloud_watch/list_metrics_test.rb new file mode 100644 index 000000000..770deb783 --- /dev/null +++ b/tests/requests/cloud_watch/list_metrics_test.rb @@ -0,0 +1,64 @@ +Shindo.tests('Aws::CloudWatch | metric requests', ['aws', 'cloudwatch']) do + + tests('success') do + @metrics_list_format = { + 'ListMetricsResult' => { + 'Metrics' => + [{ + 'Dimensions' => + [{ + 'Name' => String, + 'Value' => String + }], + "MetricName" => String, + "Namespace" => String + }], + 'NextToken' => Fog::Nullable::String, + }, + 'ResponseMetadata' => {"RequestId"=> String}, + } + @instanceId = 'i-2f3eab59' + @dimension_filtered_metrics_list_format = { + 'ListMetricsResult' => { + 'Metrics' => + [{ + 'Dimensions' => + [{ + 'Name' => 'InstanceId', + 'Value' => @instanceId + }], + "MetricName" => String, + "Namespace" => String + }], + 'NextToken' => Fog::Nullable::String, + }, + 'ResponseMetadata' => {"RequestId"=> String}, + } + + tests("#list_metrics").formats(@metrics_list_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_watch].list_metrics.body + end + + tests("#dimension_filtered_list_metrics").formats(@dimension_filtered_metrics_list_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_watch].list_metrics('Dimensions' => [{'Name' => 'InstanceId', 'Value' => @instanceId}]).body + end + + tests("#metric_name_filtered_list_metrics").returns(true) do + pending if Fog.mocking? + metricName = "CPUUtilization" + Fog::AWS[:cloud_watch].list_metrics('MetricName' => metricName).body['ListMetricsResult']['Metrics'].all? do |metric| + metric['MetricName'] == metricName + end + end + + tests("#namespace_filtered_list_metrics").returns(true) do + pending if Fog.mocking? + namespace = "Aws/EC2" + Fog::AWS[:cloud_watch].list_metrics('Namespace' => namespace).body['ListMetricsResult']['Metrics'].all? do |metric| + metric['Namespace'] == namespace + end + end + end +end diff --git a/tests/requests/cloud_watch/put_metric_data_tests.rb b/tests/requests/cloud_watch/put_metric_data_tests.rb new file mode 100644 index 000000000..3943733b4 --- /dev/null +++ b/tests/requests/cloud_watch/put_metric_data_tests.rb @@ -0,0 +1,36 @@ +Shindo.tests('Aws::CloudWatch | metric requests', ['aws', 'cloudwatch']) do + tests('success') do + + namespace = 'Custom/Test' + @puts_format = {'ResponseMetadata' => {'RequestId' => String}} + + tests('#puts_value').formats(@puts_format) do + pending if Fog.mocking? + Fog::AWS[:cloud_watch].put_metric_data(namespace, [{'MetricName' => 'RequestTest', 'Unit' => 'None', 'Value' => 1}]).body + end + + tests('#puts_statistics_set').succeeds do + pending if Fog.mocking? + Fog::AWS[:cloud_watch].put_metric_data(namespace, [{'MetricName' => 'RequestTest', 'Unit' => 'None', 'StatisticValues' => {'Minimum' => 0, 'Maximum' => 9, 'Sum' => 45, 'SampleCount' => 10, 'Average' => 4.5}}]).body + end + + tests('#puts with dimensions').succeeds do + pending if Fog.mocking? + dimensions = [{}] + Fog::AWS[:cloud_watch].put_metric_data(namespace, [{'MetricName' => 'RequestTest', 'Unit' => 'None', 'Value' => 1, 'Dimensions' => dimensions}]).body + end + + tests('#puts more than one').succeeds do + pending if Fog.mocking? + datapoints = (0...3).map do |i| + dp = {'MetricName' => "#{i}RequestTest", 'Unit' => 'None', 'Value' => i} + if i%2==0 + dp['Dimensions'] = [{'Name' => 'Ruler', 'Value' => "measurement_#{i}"}] + end + dp + end + Fog::AWS[:cloud_watch].put_metric_data(namespace, datapoints).body + end + + end +end diff --git a/tests/requests/compute/address_tests.rb b/tests/requests/compute/address_tests.rb new file mode 100644 index 000000000..a45abd660 --- /dev/null +++ b/tests/requests/compute/address_tests.rb @@ -0,0 +1,108 @@ +Shindo.tests('Fog::Compute[:aws] | address requests', ['aws']) do + + @addresses_format = { + 'addressesSet' => [{ + 'allocationId' => Fog::Nullable::String, + 'associationId' => Fog::Nullable::String, + 'domain' => String, + 'instanceId' => Fog::Nullable::String, + 'publicIp' => String + }], + 'requestId' => String + } + @server = Fog::Compute[:aws].servers.create + @server.wait_for { ready? } + @ip_address = @server.public_ip_address + + tests('success') do + + @public_ip = nil + @vpc_public_ip = nil + @vpc_allocation_id = nil + + tests('#allocate_address').formats({'domain' => String, 'publicIp' => String, 'requestId' => String}) do + data = Fog::Compute[:aws].allocate_address.body + @public_ip = data['publicIp'] + data + end + + tests("#allocate_address('vpc')").formats({'domain' => String, 'publicIp' => String, 'allocationId' => String, 'requestId' => String}) do + data = Fog::Compute[:aws].allocate_address('vpc').body + @vpc_public_ip = data['publicIp'] + @vpc_allocation_id = data['allocationId'] + data + end + + tests('#describe_addresses').formats(@addresses_format) do + Fog::Compute[:aws].describe_addresses.body + end + + tests("#describe_addresses('public-ip' => #{@public_ip}')").formats(@addresses_format) do + Fog::Compute[:aws].describe_addresses('public-ip' => @public_ip).body + end + + tests("#associate_addresses('#{@server.identity}', '#{@public_ip}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].associate_address(@server.identity, @public_ip).body + end + + tests("#associate_addresses({:instance_id=>'#{@server.identity}', :public_ip=>'#{@public_ip}'})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].associate_address({:instance_id=>@server.identity,:public_ip=> @public_ip}).body + end + + tests("#dissassociate_address('#{@public_ip}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].disassociate_address(@public_ip).body + end + + tests("#associate_addresses('#{@server.id}', nil, nil, '#{@vpc_allocation_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].associate_address(@server.id, nil, nil, @vpc_allocation_id).body + end + + tests("#associate_addresses({:instance_id=>'#{@server.id}', :allocation_id=>'#{@vpc_allocation_id}'})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].associate_address({:instance_id=>@server.id, :allocation_id=>@vpc_allocation_id}).body + end + + tests("#release_address('#{@public_ip}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].release_address(@public_ip).body + end + + tests("#release_address('#{@vpc_allocation_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].release_address(@vpc_allocation_id).body + end + end + tests('failure') do + + @address = Fog::Compute[:aws].addresses.create + @vpc_address = Fog::Compute[:aws].addresses.create(:domain => 'vpc') + + tests("#associate_addresses({:instance_id =>'i-00000000', :public_ip => '#{@address.identity}')}").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].associate_address({:instance_id => 'i-00000000', :public_ip => @address.identity}) + end + + tests("#associate_addresses({:instance_id =>'#{@server.identity}', :public_ip => '127.0.0.1'})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].associate_address({:instance_id => @server.identity, :public_ip => '127.0.0.1'}) + end + + tests("#associate_addresses({:instance_id =>'i-00000000', :public_ip => '127.0.0.1'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].associate_address({:instance_id =>'i-00000000', :public_ip =>'127.0.0.1'}) + end + + tests("#disassociate_addresses('127.0.0.1') raises BadRequest error").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].disassociate_address('127.0.0.1') + end + + tests("#release_address('127.0.0.1')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].release_address('127.0.0.1') + end + + tests("#release_address('#{@vpc_address.identity}')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].release_address(@vpc_address.identity) + end + + @address.destroy + @vpc_address.destroy + + end + + @server.destroy + +end diff --git a/tests/requests/compute/assign_private_ip_tests.rb b/tests/requests/compute/assign_private_ip_tests.rb new file mode 100644 index 000000000..94028d3cf --- /dev/null +++ b/tests/requests/compute/assign_private_ip_tests.rb @@ -0,0 +1,55 @@ +Shindo.tests('Fog::Compute[:aws] | internet_gateway requests', ['aws']) do + + tests('success') do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @vpc_id = @vpc.id + + @subnet=Fog::Compute[:aws].subnets.create('vpc_id' => @vpc_id, 'cidr_block' => '10.0.10.0/24') + @subnet_id = @subnet.subnet_id + + @network_interface = Fog::Compute[:aws].network_interfaces.new(:subnet_id => @subnet_id) + @network_interface.save + @network_interface_id = @network_interface.network_interface_id + + @ip_address = Fog::AWS::Mock.ip_address + @second_ip_address = Fog::AWS::Mock.ip_address + + tests("#assign_private_ip_addresses('#{@network_interface_id}', {'PrivateIpAddresses'=>['#{@ip_address}','#{@second_ip_address}']})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].assign_private_ip_addresses(@network_interface_id, { 'PrivateIpAddresses' =>[@ip_address, @second_ip_address]}).body + end + + tests("#assign_private_ip_addresses('#{@network_interface_id}', {'SecondaryPrivateIpAddressCount'=>4})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].assign_private_ip_addresses(@network_interface_id, {'SecondaryPrivateIpAddressCount'=>4}).body + end + + @network_interface.destroy + @subnet.destroy + @vpc.destroy + end + + tests('failure') do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @vpc_id = @vpc.id + + @subnet=Fog::Compute[:aws].subnets.create('vpc_id' => @vpc_id, 'cidr_block' => '10.0.10.0/24') + @subnet_id = @subnet.subnet_id + + @network_interface = Fog::Compute[:aws].network_interfaces.new(:subnet_id => @subnet_id) + @network_interface.save + @network_interface_id = @network_interface.network_interface_id + + @ip_address = Fog::AWS::Mock.ip_address + + tests("#assign_private_ip_addresses('#{@network_interface_id}', {'PrivateIpAddresses'=>['#{@ip_address}','#{@second_ip_address}'], 'SecondaryPrivateIpAddressCount'=>4 })").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].assign_private_ip_addresses(@network_interface_id, { 'PrivateIpAddresses' =>[@ip_address, @second_ip_address], 'SecondaryPrivateIpAddressCount'=>4 }).body + end + + @network_interface.destroy + @subnet.destroy + @vpc.destroy + end +end diff --git a/tests/requests/compute/availability_zone_tests.rb b/tests/requests/compute/availability_zone_tests.rb new file mode 100644 index 000000000..d86df012a --- /dev/null +++ b/tests/requests/compute/availability_zone_tests.rb @@ -0,0 +1,25 @@ +Shindo.tests('Fog::Compute[:aws] | availability zone requests', ['aws']) do + + @availability_zones_format = { + 'availabilityZoneInfo' => [{ + 'messageSet' => [], + 'regionName' => String, + 'zoneName' => String, + 'zoneState' => String + }], + 'requestId' => String + } + + tests('success') do + + tests('#describe_availability_zones').formats(@availability_zones_format) do + Fog::Compute[:aws].describe_availability_zones.body + end + + tests("#describe_availability_zones('zone-name' => 'us-east-1a')").formats(@availability_zones_format) do + Fog::Compute[:aws].describe_availability_zones('zone-name' => 'us-east-1a').body + end + + end + +end diff --git a/tests/requests/compute/client_tests.rb b/tests/requests/compute/client_tests.rb new file mode 100644 index 000000000..6ef2bb275 --- /dev/null +++ b/tests/requests/compute/client_tests.rb @@ -0,0 +1,25 @@ +Shindo.tests('Fog::Compute[:aws] | account tests', ['aws']) do + if Fog.mocking? + tests('check for vpc') do + tests('supports both vpc and ec2 in compatibility mode').succeeds do + client = Fog::Compute[:aws] + client.enable_ec2_classic + data = Fog::Compute[:aws].describe_account_attributes.body + data['accountAttributeSet'].any? { |s| [*s["values"]].include?("VPC") && [*s["values"]].include?("EC2") } + end + tests('supports VPC in vpc mode').succeeds do + client = Fog::Compute[:aws] + client.enable_ec2_classic + data = Fog::Compute[:aws].describe_account_attributes.body + data['accountAttributeSet'].any? { |s| [*s["values"]].include?("VPC") } + end + + tests('does not support VPC and EC2 in vpc mode').succeeds do + client = Fog::Compute[:aws] + client.disable_ec2_classic + data = Fog::Compute[:aws].describe_account_attributes.body + !data['accountAttributeSet'].any? { |s| [*s["values"]].include?("VPC") && [*s["values"]].include?("EC2") } + end + end + end +end diff --git a/tests/requests/compute/dhcp_options_tests.rb b/tests/requests/compute/dhcp_options_tests.rb new file mode 100644 index 000000000..b590ad618 --- /dev/null +++ b/tests/requests/compute/dhcp_options_tests.rb @@ -0,0 +1,39 @@ +Shindo.tests('Fog::Compute[:aws] | dhcp_options requests', ['aws']) do + + @dhcp_options_format = { + 'dhcpOptionsSet' => [{ + 'dhcpOptionsId' => String, + 'dhcpConfigurationSet' => Hash, + 'tagSet' => Fog::Nullable::Hash, + }], + 'requestId' => String + } + + tests('success') do + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @vpc_id = @vpc.id + + tests('#create_dhcp_options').formats(@dhcp_options_format) do + data = Fog::Compute[:aws].create_dhcp_options({'domain-name' => 'example.com', 'domain-name-servers' => '10.10.10.10'}).body + @dopt_id = data['dhcpOptionsSet'].first['dhcpOptionsId'] + data + end + + tests('#describe_dhcp_options').formats(@dhcp_options_format) do + Fog::Compute[:aws].describe_dhcp_options.body + end + + tests("#associate_dhcp_options('#{@dopt_id}, #{@vpc_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].associate_dhcp_options(@dopt_id, @vpc_id).body + end + + tests("#associate_default_dhcp_options('default', #{@vpc_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].associate_dhcp_options('default', @vpc_id).body + end + + tests("#delete_dhcp_options('#{@dopt_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_dhcp_options(@dopt_id).body + end + @vpc.destroy + end +end diff --git a/tests/requests/compute/helper.rb b/tests/requests/compute/helper.rb new file mode 100644 index 000000000..faf95e7dc --- /dev/null +++ b/tests/requests/compute/helper.rb @@ -0,0 +1,10 @@ +class Aws + module Compute + module Formats + BASIC = { + 'requestId' => String, + 'return' => ::Fog::Boolean + } + end + end +end diff --git a/tests/requests/compute/image_tests.rb b/tests/requests/compute/image_tests.rb new file mode 100644 index 000000000..fd7a4fb83 --- /dev/null +++ b/tests/requests/compute/image_tests.rb @@ -0,0 +1,158 @@ +Shindo.tests('Fog::Compute[:aws] | image requests', ['aws']) do + @describe_images_format = { + 'imagesSet' => [{ + 'architecture' => String, + 'blockDeviceMapping' => [Fog::Nullable::Hash], + 'description' => Fog::Nullable::String, + 'hypervisor' => String, + 'imageId' => String, + 'imageLocation' => String, + 'imageOwnerAlias' => Fog::Nullable::String, + 'imageOwnerId' => String, + 'imageState' => String, + 'imageType' => String, + 'isPublic' => Fog::Boolean, + 'kernelId' => String, + 'name' => String, + 'platform' => Fog::Nullable::String, + 'productCodes' => [], + 'ramdiskId' => Fog::Nullable::String, + 'rootDeviceName' => String, + 'rootDeviceType' => String, + 'stateReason' => {}, + 'tagSet' => {}, + 'virtualizationType' => String + }], + 'requestId' => String, + } + + @register_image_format = { + 'imageId' => String, + 'requestId' => String + } + + @modify_image_attribute_format = { + 'return' => Fog::Boolean, + 'requestId' => String + } + @create_image_format = { + 'requestId' => String, + 'imageId' => String + } + + @image_copy_result = { + 'requestId' => String, + 'imageId' => String + } + + tests('success') do + # the result for this is HUGE and relatively uninteresting... + # tests("#describe_images").formats(@images_format) do + # Fog::Compute[:aws].describe_images.body + # end + @image_id = 'ami-1aad5273' + + if Fog.mocking? + @other_account = Fog::Compute::AWS.new(:aws_access_key_id => 'other', :aws_secret_access_key => 'account') + + @server = Fog::Compute[:aws].servers.create + @server.wait_for{state == 'running'} + @created_image + tests("#create_image").formats(@create_image_format) do + result = Fog::Compute[:aws].create_image(@server.id, 'Fog-Test-Image', 'Fog Test Image', false).body + @created_image = Fog::Compute[:aws].images.get(result['imageId']) + result + end + tests("#create_image - no reboot").formats(@create_image_format) do + result = Fog::Compute[:aws].create_image(@server.id, 'Fog-Test-Image', 'Fog Test Image', true).body + @created_image = Fog::Compute[:aws].images.get(result['imageId']) + result + end + tests("#create_image - automatic ebs image registration").returns(true) do + create_image_response = Fog::Compute[:aws].create_image(@server.id, 'Fog-Test-Image', 'Fog Test Image') + Fog::Compute[:aws].images.get(create_image_response.body['imageId']) != nil + end + @server.destroy + + tests("#copy_image (#{@image_id}, 'eu-west-1')").formats(@image_copy_result) do + data = Fog::Compute.new(:provider => :aws, :region => "us-west-1", :version => "2013-02-01").copy_image(@image_id, "eu-east-1").body + @eu_image_id = data['imageId'] + data + end + + tests("#register_image").formats(@register_image_format) do + @image = Fog::Compute[:aws].register_image('image', 'image', '/dev/sda1').body + end + + tests("#register_image - with ebs block device mapping").formats(@register_image_format) do + @ebs_image = Fog::Compute[:aws].register_image('image', 'image', '/dev/sda1', [ { 'DeviceName' => '/dev/sdh', "SnapshotId" => "snap-123456789", "VolumeSize" => "10G", "DeleteOnTermination" => true}]).body + end + + tests("#register_image - with ephemeral block device mapping").formats(@register_image_format) do + @ephemeral_image = Fog::Compute[:aws].register_image('image', 'image', '/dev/sda1', [ { 'VirtualName' => 'ephemeral0', "DeviceName" => "/dev/sdb"} ]).body + end + + @image_id = @image['imageId'] + sleep 1 + + tests("#describe_images('Owner' => 'self')").formats(@describe_images_format) do + Fog::Compute[:aws].describe_images('Owner' => 'self').body + end + + tests("#describe_images('state' => 'available')").formats(@describe_images_format) do + Fog::Compute[:aws].describe_images('state' => 'available').body + end + + tests("other_account#describe_images('image-id' => '#{@image_id}')").returns([]) do + @other_account.describe_images('image-id' => @image_id).body['imagesSet'] + end + + tests("#modify_image_attribute('#{@image_id}', 'Add.UserId' => ['#{@other_account.data[:owner_id]}'])").formats(@modify_image_attribute_format) do + Fog::Compute[:aws].modify_image_attribute(@image_id, { 'Add.UserId' => [@other_account.data[:owner_id]] }).body + end + + tests("other_account#describe_images('image-id' => '#{@image_id}')").returns([@image_id]) do + @other_account.describe_images('image-id' => @image_id).body['imagesSet'].map {|i| i['imageId'] } + end + + tests("#modify_image_attribute('#{@image_id}', 'Remove.UserId' => ['#{@other_account.data[:owner_id]}'])").formats(@modify_image_attribute_format) do + Fog::Compute[:aws].modify_image_attribute(@image_id, { 'Remove.UserId' => [@other_account.data[:owner_id]] }).body + end + + tests("other_account#describe_images('image-id' => '#{@image_id}')").returns([]) do + @other_account.describe_images('image-id' => @image_id).body['imagesSet'] + end + end + + tests("#describe_images('image-id' => '#{@image_id}')").formats(@describe_images_format) do + @other_image = Fog::Compute[:aws].describe_images('image-id' => @image_id).body + end + + unless Fog.mocking? + tests("#describe_images('Owner' => '#{@other_image['imageOwnerAlias']}', 'image-id' => '#{@image_id}')").formats(@describe_images_format) do + Fog::Compute[:aws].describe_images('Owner' => @other_image['imageOwnerAlias'], 'image-id' => @image_id).body + end + end + + #NOTE: waiting for the image to complete can sometimes take up to 1 hour + # for quicker tests: uncomment the rest of this block + #Fog.wait_for { Fog::Compute.new(:provider => :aws, :region => "us-west-1").snapshots.get(@eu_image_id) } + + #tests("#delete_snapshots(#{@eu_image_id})").formats(Aws::Compute::Formats::BASIC) do + # Fog::Compute.new(:provider => :aws, :region => "us-west-1").delete_snapshot(@eu_image_id).body + #end + + end + + tests('failure') do + tests("#modify_image_attribute(nil, { 'Add.Group' => ['all'] })").raises(ArgumentError) do + Fog::Compute[:aws].modify_image_attribute(nil, { 'Add.Group' => ['all'] }).body + end + + tests("#modify_image_attribute('ami-00000000', { 'Add.UserId' => ['123456789012'] })").raises(Fog::Compute::AWS::NotFound) do + pending unless Fog.mocking? + + Fog::Compute[:aws].modify_image_attribute('ami-00000000', { 'Add.UserId' => ['123456789012'] }).body + end + end +end diff --git a/tests/requests/compute/instance_tests.rb b/tests/requests/compute/instance_tests.rb new file mode 100644 index 000000000..4346c9563 --- /dev/null +++ b/tests/requests/compute/instance_tests.rb @@ -0,0 +1,297 @@ +Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do + + @instance_format = { + 'architecture' => String, + 'amiLaunchIndex' => Integer, + 'associatePublicIP' => Fog::Nullable::Boolean, + 'attachmentId' => Fog::Nullable::String, + 'blockDeviceMapping' => [Fog::Nullable::Hash], + 'networkInterfaces' => [Fog::Nullable::Hash], + 'clientToken' => Fog::Nullable::String, + 'dnsName' => NilClass, + 'ebsOptimized' => Fog::Boolean, + 'imageId' => String, + 'instanceId' => String, + 'instanceState' => {'code' => Integer, 'name' => String}, + 'instanceType' => String, + 'kernelId' => Fog::Nullable::String, + 'keyName' => Fog::Nullable::String, + 'launchTime' => Time, + 'monitoring' => {'state' => Fog::Boolean}, + 'networkInterfaceId' => Fog::Nullable::String, + 'placement' => { + 'availabilityZone' => String, + 'groupName' => Fog::Nullable::String, + 'tenancy' => String + }, + 'platform' => Fog::Nullable::String, + 'privateDnsName' => NilClass, + 'productCodes' => Array, + 'reason' => Fog::Nullable::String, + 'rootDeviceName' => Fog::Nullable::String, + 'rootDeviceType' => String, + 'sourceDestCheck' => Fog::Nullable::Boolean, + 'subnetId' => Fog::Nullable::String, + 'vpcId' => Fog::Nullable::String + } + + @run_instances_format = { + 'groupSet' => [String], + 'instancesSet' => [@instance_format], + 'ownerId' => Fog::Nullable::String, + 'requestId' => String, + 'reservationId' => String + } + + @describe_instances_format = { + 'reservationSet' => [{ + 'groupSet' => [String], + 'groupIds' => [String], + 'instancesSet' => [@instance_format.merge( + 'architecture' => String, + 'dnsName' => Fog::Nullable::String, + 'hypervisor' => String, + 'iamInstanceProfile' => Hash, + 'ipAddress' => Fog::Nullable::String, + 'networkInterfaces' => Array, + 'ownerId' => String, + 'privateDnsName' => Fog::Nullable::String, + 'privateIpAddress' => Fog::Nullable::String, + 'stateReason' => Hash, + 'tagSet' => Hash, + 'virtualizationType' => String + )], + 'ownerId' => Fog::Nullable::String, + 'reservationId' => String + }], + 'requestId' => String + } + + @get_console_output_format = { + 'instanceId' => String, + 'output' => Fog::Nullable::String, + 'requestId' => String, + 'timestamp' => Time + } + + @get_password_data_format = { + 'instanceId' => String, + 'passwordData' => Fog::Nullable::String, + 'requestId' => String, + 'timestamp' => Time + } + + @terminate_instances_format = { + 'instancesSet' => [{ + 'currentState' => {'code' => Integer, 'name' => String}, + 'instanceId' => String, + 'previousState' => {'code' => Integer, 'name' => String}, + }], + 'requestId' => String + } + + @describe_reserved_instances_offerings_format = { + 'reservedInstancesOfferingsSet' => [{ + 'reservedInstancesOfferingId' => String, + 'instanceType' => String, + 'availabilityZone' => String, + 'duration' => Integer, + 'fixedPrice' => Float, + 'offeringType' => String, + 'usagePrice' => Float, + 'productDescription' => String, + 'instanceTenancy' => String, + 'currencyCode' => String + }], + 'requestId' => String + } + + @purchase_reserved_instances_offering_format = { + 'reservedInstancesId' => String, + 'requestId' => String + } + + @describe_reserved_instances_format = { + 'reservedInstancesSet' => [{ + 'reservedInstancesId' => String, + 'instanceType' => String, + 'availabilityZone' => String, + 'start' => Time, + 'end' => Time, + 'duration' => Integer, + 'fixedPrice' => Float, + 'usagePrice' => Float, + 'instanceCount' => Integer, + 'offeringType' => String, + 'productDescription' => String, + 'state' => String, + 'tagSet' => [{ + 'key' => String, + 'value' => String + }], + 'instanceTenancy' => String, + 'currencyCode' => String + }], + 'requestId' => String + } + + @describe_instance_status_format = { + 'requestId' => String, + 'instanceStatusSet' => [{ + 'instanceId' => String, + 'availabilityZone' => String, + 'instanceState' => { + 'code' => Integer, + 'name' => String + }, + 'systemStatus' => { + 'status' => String, + 'details' => [{ + 'name' => String, + 'status' => String + }] + }, + 'instanceStatus' => { + 'status' => String, + 'details' => [{ + 'name' => String, + 'status' => String + }] + }, + 'eventsSet' => [Fog::Nullable::Hash], + }] + } + tests('success') do + + @instance_id = nil + @ami = if ENV['FASTER_TEST_PLEASE'] + 'ami-79c0ae10' # ubuntu 12.04 daily build 20120728 + else + # Use a MS Windows AMI to test #get_password_data + 'ami-71b50018' # Amazon Public Images - Windows_Server-2008-SP2-English-64Bit-Base-2012.07.11 + end + + # Create a keypair for decrypting the password + key_name = 'fog-test-key' + key = Fog::Compute[:aws].key_pairs.create(:name => key_name) + + tests("#run_instances").formats(@run_instances_format) do + data = Fog::Compute[:aws].run_instances(@ami, 1, 1, 'InstanceType' => 't1.micro', 'KeyName' => key_name, 'BlockDeviceMapping' => [{"DeviceName" => "/dev/sdp1", "VirtualName" => nil, "Ebs.VolumeSize" => 15}]).body + @instance_id = data['instancesSet'].first['instanceId'] + data + end + + server = Fog::Compute[:aws].servers.get(@instance_id) + while server.nil? do + # It may take a moment to get the server after launching it + sleep 0.1 + server = Fog::Compute[:aws].servers.get(@instance_id) + end + server.wait_for { ready? } + + tests("#describe_instances").formats(@describe_instances_format) do + Fog::Compute[:aws].describe_instances('instance-state-name' => 'running').body + end + + # Launch another instance to test filters + another_server = Fog::Compute[:aws].servers.create + + tests("#describe_instances('instance-id' => '#{@instance_id}'").formats(@describe_instances_format) do + body = Fog::Compute[:aws].describe_instances('instance-id' => "#{@instance_id}").body + tests("returns 1 instance").returns(1) { body['reservationSet'].size } + body + end + + # Test network interface attachment + tests('#describe_instances networkInterfaces') do + vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/16') + subnet = Fog::Compute[:aws].subnets.create('vpc_id' => vpc.id, 'cidr_block' => '10.0.10.0/16') + data = Fog::Compute[:aws].create_network_interface(subnet.subnet_id).body + @network_interface_id = data['networkInterface']['networkInterfaceId'] + Fog::Compute[:aws].attach_network_interface(@network_interface_id, @instance_id, '1') + body = Fog::Compute[:aws].describe_instances('instance-id' => "#{@instance_id}").body + tests("returns 1 attachment").returns(1) { body['reservationSet'].first['instancesSet'].first['networkInterfaces'].size } + subnet.destroy + vpc.destroy + end + + another_server.destroy + + tests("#get_console_output('#{@instance_id}')").formats(@get_console_output_format) do + Fog::Compute[:aws].get_console_output(@instance_id).body + end + + tests("#get_password_data('#{@instance_id}')").formats(@get_password_data_format) do + result = Fog::Compute[:aws].get_password_data(@instance_id).body + + tests("key can decrypt passwordData").returns(true) do + + pending if Fog.mocking? + + password_data = result['passwordData'] + Fog.wait_for do + password_data ||= Fog::Compute[:aws].get_password_data(@instance_id).body['passwordData'] + end + + decoded_password = Base64.decode64(password_data) + pkey = OpenSSL::PKey::RSA.new(key.private_key) + String === pkey.private_decrypt(decoded_password) + end + result + end unless ENV['FASTER_TEST_PLEASE'] + + key.destroy + + tests("#reboot_instances('#{@instance_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].reboot_instances(@instance_id).body + end + + tests("#terminate_instances('#{@instance_id}')").formats(@terminate_instances_format) do + Fog::Compute[:aws].terminate_instances(@instance_id).body + end + + tests("#describe_reserved_instances_offerings").formats(@describe_reserved_instances_offerings_format) do + @reserved_instances = Fog::Compute[:aws].describe_reserved_instances_offerings.body + @reserved_instances + end + + tests('#describe_instance_status').formats(@describe_instance_status_format) do + Fog::Compute[:aws].describe_instance_status.body + end + + if Fog.mocking? + @reserved_instance_offering_id = @reserved_instances["reservedInstancesOfferingsSet"].first["reservedInstancesOfferingId"] + tests("#purchase_reserved_instances_offering('#{@reserved_instance_offering_id}')").formats(@purchase_reserved_instances_offering_format) do + Fog::Compute[:aws].purchase_reserved_instances_offering(@reserved_instance_offering_id, 1).body + end + + tests("#describe_reserved_instances").formats(@describe_reserved_instances_format) do + Fog::Compute[:aws].describe_reserved_instances.body + end + end + end + + tests('failure') do + + tests("#run_instances(nil, 1, 1, {'SubnetId'=>'subnet-00000000'}").raises(::Fog::Compute::AWS::Error) do + Fog::Compute[:aws].run_instances(nil, 1, 1, {'SubnetId' => 'subnet-000000'}) + end + tests("#get_console_output('i-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].get_console_output('i-00000000') + end + + tests("#get_password_data('i-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].get_password_data('i-00000000') + end + + tests("#reboot_instances('i-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].reboot_instances('i-00000000') + end + + tests("#terminate_instances('i-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].terminate_instances('i-00000000') + end + + end + +end diff --git a/tests/requests/compute/internet_gateway_tests.rb b/tests/requests/compute/internet_gateway_tests.rb new file mode 100644 index 000000000..30f8d9787 --- /dev/null +++ b/tests/requests/compute/internet_gateway_tests.rb @@ -0,0 +1,49 @@ +Shindo.tests('Fog::Compute[:aws] | internet_gateway requests', ['aws']) do + + @internet_gateways_format = { + 'internetGatewaySet' => [{ + 'internetGatewayId' => String, + 'attachmentSet' => Hash, + 'tagSet' => Fog::Nullable::Hash, + }], + 'requestId' => String + } + + tests('success') do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @vpc_id = @vpc.id + @subnet=Fog::Compute[:aws].subnets.create('vpc_id' => @vpc_id, 'cidr_block' => '10.0.10.0/24') + @subnet_id = @subnet.subnet_id + @igw_id = nil + + tests('#create_internet_gateway').formats(@internet_gateways_format) do + data = Fog::Compute[:aws].create_internet_gateway().body + @igw_id = data['internetGatewaySet'].first['internetGatewayId'] + data + end + + tests('#describe_internet_gateways').formats(@internet_gateways_format) do + Fog::Compute[:aws].describe_internet_gateways.body + end + + tests('#describe_internet_gateways with tags').formats(@internet_gateways_format) do + Fog::Compute[:aws].create_tags @igw_id, {"environment" => "production"} + Fog::Compute[:aws].describe_internet_gateways.body + end + + tests("#attach_internet_gateway('#{@igw_id}, #{@vpc_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].attach_internet_gateway(@igw_id, @vpc_id).body + end + + tests("#detach_internet_gateway('#{@igw_id}, #{@vpc_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].detach_internet_gateway(@igw_id, @vpc_id).body + end + + tests("#delete_internet_gateway('#{@igw_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_internet_gateway(@igw_id).body + end + @subnet.destroy + @vpc.destroy + end +end diff --git a/tests/requests/compute/key_pair_tests.rb b/tests/requests/compute/key_pair_tests.rb new file mode 100644 index 000000000..65e6f58f4 --- /dev/null +++ b/tests/requests/compute/key_pair_tests.rb @@ -0,0 +1,67 @@ +Shindo.tests('Fog::Compute[:aws] | key pair requests', ['aws']) do + + tests('success') do + + @keypair_format = { + 'keyFingerprint' => String, + 'keyName' => String, + 'requestId' => String + } + + @keypairs_format = { + 'keySet' => [{ + 'keyFingerprint' => String, + 'keyName' => String + }], + 'requestId' => String + } + + @key_pair_name = 'fog_create_key_pair' + @public_key_material = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA1SL+kgze8tvSFW6Tyj3RyZc9iFVQDiCKzjgwn2tS7hyWxaiDhjfY2mBYSZwFdKN+ZdsXDJL4CPutUg4DKoQneVgIC1zuXrlpPbaT0Btu2aFd4qNfJ85PBrOtw2GrWZ1kcIgzZ1mMbQt6i1vhsySD2FEj+5kGHouNxQpI5dFR5K+nGgcTLFGnzb/MPRBk136GVnuuYfJ2I4va/chstThoP8UwnoapRHcBpwTIfbmmL91BsRVqjXZEUT73nxpxFeXXidYwhHio+5dXwE0aM/783B/3cPG6FVoxrBvjoNpQpAcEyjtRh9lpwHZtSEW47WNzpIW3PhbQ8j4MryznqF1Rhw==' + + tests("#create_key_pair('#{@key_pair_name}')").formats(@keypair_format.merge({'keyMaterial' => String})) do + body = Fog::Compute[:aws].create_key_pair(@key_pair_name).body + tests("key material").returns(OpenSSL::PKey::RSA, "is a valid private RSA key") do + OpenSSL::PKey::RSA.new(body['keyMaterial']).class + end + body + end + + tests('#describe_key_pairs').formats(@keypairs_format) do + Fog::Compute[:aws].describe_key_pairs.body + end + + tests("#describe_key_pairs('key-name' => '#{@key_pair_name}')").formats(@keypairs_format) do + Fog::Compute[:aws].describe_key_pairs('key-name' => @key_pair_name).body + end + + tests("#delete_key_pair('#{@key_pair_name}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_key_pair(@key_pair_name).body + end + + tests("#import_key_pair('fog_import_key_pair', '#{@public_key_material}')").formats(@keypair_format) do + Fog::Compute[:aws].import_key_pair('fog_import_key_pair', @public_key_material).body + end + + tests("#delete_key_pair('fog_import_key_pair)").succeeds do + Fog::Compute[:aws].delete_key_pair('fog_import_key_pair') + end + + tests("#delete_key_pair('not_a_key_name')").succeeds do + Fog::Compute[:aws].delete_key_pair('not_a_key_name') + end + + end + tests('failure') do + + @key_pair = Fog::Compute[:aws].key_pairs.create(:name => 'fog_key_pair') + + tests("duplicate #create_key_pair('#{@key_pair.name}')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_key_pair(@key_pair.name) + end + + @key_pair.destroy + + end + +end diff --git a/tests/requests/compute/network_acl_tests.rb b/tests/requests/compute/network_acl_tests.rb new file mode 100644 index 000000000..809a66ecf --- /dev/null +++ b/tests/requests/compute/network_acl_tests.rb @@ -0,0 +1,112 @@ +Shindo.tests('Fog::Compute[:aws] | network acl requests', ['aws']) do + + @network_acl_format = { + 'networkAclId' => String, + 'vpcId' => String, + 'default' => Fog::Boolean, + 'entrySet' => [{ + 'ruleNumber' => Integer, + 'protocol' => Integer, + 'ruleAction' => String, + 'egress' => Fog::Boolean, + 'cidrBlock' => String, + 'icmpTypeCode' => { + 'code' => Fog::Nullable::Integer, + 'type' => Fog::Nullable::Integer + }, + 'portRange' => { + 'from' => Fog::Nullable::Integer, + 'to' => Fog::Nullable::Integer + } + }], + 'associationSet' => Array, + 'tagSet' => Hash + } + + @network_acls_format = { + 'requestId' => String, + 'networkAclSet' => [ @network_acl_format ] + } + + @network_acl_replace_association = { + 'requestId' => String, + 'newAssociationId' => String + } + + tests('success') do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @subnet = Fog::Compute[:aws].subnets.create('vpc_id' => @vpc.id, 'cidr_block' => '10.0.10.16/28') + @network_acl = nil + + # Describe network interfaces + tests('#describe_network_acls').formats(@network_acls_format) do + Fog::Compute[:aws].describe_network_acls.body + end + + tests('#create_network_acl').formats(@network_acl_format) do + data = Fog::Compute[:aws].create_network_acl(@vpc.id).body + + @network_acl = data['networkAcl'] + data['networkAcl'] + end + + tests("#create_network_acl_entry").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_network_acl_entry(@network_acl['networkAclId'], 100, 6, 'allow', '0.0.0.0/8', false, 'PortRange.From' => 22, 'PortRange.To' => 22).body + end + + tests("#replace_network_acl_entry").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].replace_network_acl_entry(@network_acl['networkAclId'], 100, 6, 'deny', '0.0.0.0/8', false, 'PortRange.From' => 22, 'PortRange.To' => 22).body + end + + tests("#delete_network_acl_entry").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_network_acl_entry(@network_acl['networkAclId'], 100, false).body + end + + default_acl = Fog::Compute[:aws].describe_network_acls('vpc-id' => @vpc.id, 'default' => true).body['networkAclSet'].first + @assoc_id = default_acl['associationSet'].first['networkAclAssociationId'] + + tests("#replace_network_acl_association").formats(@network_acl_replace_association) do + data = Fog::Compute[:aws].replace_network_acl_association(@assoc_id, @network_acl['networkAclId']).body + @assoc_id = data['newAssociationId'] + data + end + + tests("#replace_network_acl_association").formats(@network_acl_replace_association) do + Fog::Compute[:aws].replace_network_acl_association(@assoc_id, default_acl['networkAclId']).body + end + + # Create another network acl to test tag filters + test_tags = {'foo' => 'bar'} + @another_acl = Fog::Compute[:aws].network_acls.create :vpc_id => @vpc.id, :tags => test_tags + tests("#describe_network_acls('tag-key' => 'foo')").formats(@network_acls_format) do + body = Fog::Compute[:aws].describe_network_acls('tag-key' => 'foo').body + tests("returns 1 acl").returns(1) { body['networkAclSet'].size } + body + end + + tests("#describe_network_acls('tag-value' => 'bar')").formats(@network_acls_format) do + body = Fog::Compute[:aws].describe_network_acls('tag-value' => 'bar').body + tests("returns 1 acl").returns(1) { body['networkAclSet'].size } + body + end + + tests("#describe_network_acls('tag:foo' => 'bar')").formats(@network_acls_format) do + body = Fog::Compute[:aws].describe_network_acls('tag:foo' => 'bar').body + tests("returns 1 acl").returns(1) { body['networkAclSet'].size } + body + end + + tests('#delete_network_acl').formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_network_acl(@network_acl['networkAclId']).body + end + + # Clean up + Fog::Compute[:aws].delete_tags(@another_acl.identity, test_tags) + @another_acl.destroy + @subnet.destroy + @vpc.destroy + Fog::Compute::AWS::Mock.reset if Fog.mocking? + end +end diff --git a/tests/requests/compute/network_interface_tests.rb b/tests/requests/compute/network_interface_tests.rb new file mode 100644 index 000000000..2afdbc858 --- /dev/null +++ b/tests/requests/compute/network_interface_tests.rb @@ -0,0 +1,250 @@ +Shindo.tests('Fog::Compute[:aws] | network interface requests', ['aws']) do + + @network_interface_format = { + 'networkInterfaceId' => String, + 'subnetId' => String, + 'vpcId' => String, + 'availabilityZone' => String, + 'description' => Fog::Nullable::String, + 'ownerId' => String, + 'requesterId' => Fog::Nullable::String, + 'requesterManaged' => String, + 'status' => String, + 'macAddress' => String, + 'privateIpAddress' => String, + 'privateDnsName' => Fog::Nullable::String, + 'sourceDestCheck' => Fog::Boolean, + 'groupSet' => Fog::Nullable::Hash, + 'attachment' => Hash, + 'association' => Hash, + 'tagSet' => Hash + } + + @network_interface_create_format = { + 'networkInterface' => @network_interface_format, + 'requestId' => String + } + + @network_interfaces_format = { + 'requestId' => String, + 'networkInterfaceSet' => [ @network_interface_format ] + } + + @attach_network_interface_format = { + 'requestId' => String, + 'attachmentId' => String + } + + tests('success') do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + + # Create environment + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @subnet = Fog::Compute[:aws].subnets.create('vpc_id' => @vpc.id, 'cidr_block' => '10.0.10.16/28') + @security_group = Fog::Compute[:aws].security_groups.create('name' => 'sg_name', 'description' => 'sg_desc', 'vpc_id' => @vpc.id) + @owner_id = Fog::Compute[:aws].describe_security_groups('group-name' => 'default').body['securityGroupInfo'].first['ownerId'] + + @subnet_id = @subnet.subnet_id + @security_group_id = @security_group.group_id + + @security_groups = [ + @security_group.name, { + 'groupDescription' => @security_group.description, + 'groupName' => @security_group.name, + 'groupId' => @security_group_id, + 'ipPermissionsEgress' => [], + 'ipPermissions' => [], + 'ownerId' => @owner_id, + 'vpcId' => @vpc.id + } + ] + + DESCRIPTION = "Small and green" + tests("#create_network_interface(#{@subnet_id})").formats(@network_interface_create_format) do + data = Fog::Compute[:aws].create_network_interface(@subnet_id, {"PrivateIpAddress" => "10.0.10.23"}).body + @nic_id = data['networkInterface']['networkInterfaceId'] + data + end + + # Describe network interfaces + tests('#describe_network_interfaces').formats(@network_interfaces_format) do + Fog::Compute[:aws].describe_network_interfaces.body + end + + # Describe network interface attribute + tests("#describe_network_interface_attribute(#{@nic_id}, 'description')").returns(nil) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic_id, 'description').body['description'] + end + + # test describe of all supported attributes + [ 'description', 'groupSet', 'sourceDestCheck', 'attachment'].each do |attrib| + tests("#describe_network_interface_attribute(#{@nic_id}, #{attrib})").returns(@nic_id) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic_id, attrib).body['networkInterfaceId'] + end + end + + # Modify network interface description attribute + tests("#modify_network_interface_attribute(#{@nic_id}, 'description', '#{DESCRIPTION}')").returns(true) do + Fog::Compute[:aws].modify_network_interface_attribute(@nic_id, 'description', DESCRIPTION).body["return"] + end + + # Describe network interface attribute again + tests("#describe_network_interface_attribute(#{@nic_id}, 'description')").returns(DESCRIPTION) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic_id, 'description').body["description"] + end + + # Restore network interface description attribute + tests("#modify_network_interface_attribute(#{@nic_id}, 'description', '')").returns(true) do + Fog::Compute[:aws].modify_network_interface_attribute(@nic_id, 'description', '').body["return"] + end + + # Check modifying the group set + tests("#modify_network_interface_attribute(#{@nic_id}, 'groupSet', [#{@security_group_id}])").returns(true) do + Fog::Compute[:aws].modify_network_interface_attribute(@nic_id, 'groupSet', [@security_group_id]).body["return"] + end + tests("#describe_network_interface_attribute(#{@nic_id}, 'groupSet')").returns({ @security_group_id => "sg_name" }) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic_id, 'groupSet').body["groupSet"] + end + + # Check modifying the source dest check (and reset) + tests("#modify_network_interface_attribute(#{@nic_id}, 'sourceDestCheck', false)").returns(true) do + Fog::Compute[:aws].modify_network_interface_attribute(@nic_id, 'sourceDestCheck', false).body["return"] + end + tests("#describe_network_interface_attribute(#{@nic_id}, 'sourceDestCheck')").returns(false) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic_id, 'sourceDestCheck').body["sourceDestCheck"] + end + tests("#reset_network_interface_attribute(#{@nic_id}, 'sourceDestCheck')").returns(true) do + Fog::Compute[:aws].reset_network_interface_attribute(@nic_id, 'sourceDestCheck').body["return"] + end + tests("#describe_network_interface_attribute(#{@nic_id}, 'sourceDestCheck')").returns(true) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic_id, 'sourceDestCheck').body["sourceDestCheck"] + end + + @server = Fog::Compute[:aws].servers.create({:flavor_id => 'm1.small', :subnet_id => @subnet_id }) + @server.wait_for { ready? } + @instance_id=@server.id + + # attach + @device_index = 1 + tests('#attach_network_interface').formats(@attach_network_interface_format) do + data = Fog::Compute[:aws].attach_network_interface(@nic_id, @instance_id, @device_index).body + @attachment_id = data['attachmentId'] + data + end + + # Check modifying the attachment + attach_attr = { + 'attachmentId' => @attachment_id, + 'deleteOnTermination' => true + } + tests("#modify_network_interface_attribute(#{@nic_id}, 'attachment', #{attach_attr.inspect})").returns(true) do + Fog::Compute[:aws].modify_network_interface_attribute(@nic_id, 'attachment', attach_attr).body["return"] + end + + # detach + tests('#detach_network_interface').returns(true) do + Fog::Compute[:aws].detach_network_interface(@attachment_id,true).body["return"] + end + if !Fog.mocking? + Fog::Compute[:aws].network_interfaces.get(@nic_id).wait_for { status == 'available'} + end + # Create network interface with arguments + options = { + "PrivateIpAddress" => "10.0.10.24", + "Description" => DESCRIPTION, + "GroupSet" => [@security_group_id] + } + tests("#create_network_interface(#{@subnet_id}), #{options.inspect}").returns("10.0.10.24") do + data = Fog::Compute[:aws].create_network_interface(@subnet_id, options).body + @nic2_id = data['networkInterface']['networkInterfaceId'] + data['networkInterface']['privateIpAddress'] + end + + # Check assigned values + tests("#describe_network_interface_attribute(#{@nic2_id}, 'description')").returns(DESCRIPTION) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic2_id, 'description').body["description"] + end + tests("#describe_network_interface_attribute(#{@nic2_id}, 'groupSet')").returns({ @security_group_id => @security_groups }) do + Fog::Compute[:aws].describe_network_interface_attribute(@nic2_id, 'groupSet').body["groupSet"] + end + + # Delete network interfaces + tests("#delete_network_interface('#{@nic2_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_network_interface(@nic2_id).body + end + tests("#delete_network_interface('#{@nic_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_network_interface(@nic_id).body + end + + @server.destroy + if !Fog.mocking? + @server.wait_for { state == 'terminated' } + # despite the fact that the state goes to 'terminated' we need a little delay for aws to do its thing + sleep 5 + end + + # Bring up another server to test vpc public IP association + @server = Fog::Compute[:aws].servers.create(:flavor_id => 'm1.small', :subnet_id => @subnet_id, :associate_public_ip => true) + @server.wait_for { ready? } + @instance_id = @server.id + + test("#associate_public_ip") do + server = Fog::Compute[:aws].servers.get(@instance_id) + server.public_ip_address.nil? == false + end + + # Clean up resources + @server.destroy + if !Fog.mocking? + @server.wait_for { state == 'terminated' } + # despite the fact that the state goes to 'terminated' we need a little delay for aws to do its thing + sleep 5 + end + @security_group.destroy + @subnet.destroy + @vpc.destroy + end + + tests('failure') do + + # Attempt to attach a nonexistent interface + tests("#attach_network_interface('eni-00000000', 'i-00000000', '1')").raises(::Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].attach_network_interface('eni-00000000', 'i-00000000', '1') + end + + # Create environment + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @subnet = Fog::Compute[:aws].subnets.create('vpc_id' => @vpc.id, 'cidr_block' => '10.0.10.16/28') + + @subnet_id = @subnet.subnet_id + + data = Fog::Compute[:aws].create_network_interface(@subnet_id).body + @nic_id = data['networkInterface']['networkInterfaceId'] + + # Attempt to re-use an existing IP for another ENI + tests("#create_network_interface('#{@subnet_id}', " \ + "{'PrivateIpAddress' => " \ + "'#{data['networkInterface']['privateIpAddress']}'}").raises(::Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_network_interface(@subnet_id, {'PrivateIpAddress' => data['networkInterface']['privateIpAddress']}) + end + + # Attempt to attach a valid ENI to a nonexistent instance. + tests("#attach_network_interface('#{@nic_id}', 'i-00000000', '0')").raises(::Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].attach_network_interface(@nic_id, 'i-00000000', '0') + end + + @server = Fog::Compute[:aws].servers.create({:flavor_id => 'm1.small', :subnet_id => @subnet_id }) + @server.wait_for { ready? } + @instance_id=@server.id + @device_index = 1 + data = Fog::Compute[:aws].attach_network_interface(@nic_id, @instance_id, @device_index).body + + # Attempt to attach two ENIs to the same instance with the same device + # index. + tests("#attach_network_interface('#{@nic_id}', '#{@instance_id}', '#{@device_index}')").raises(::Fog::Compute::AWS::Error) do + Fog::Compute[:aws].attach_network_interface(@nic_id, @instance_id, @device_index) + end + + Fog::Compute::AWS::Mock.reset if Fog.mocking? + end +end diff --git a/tests/requests/compute/placement_group_tests.rb b/tests/requests/compute/placement_group_tests.rb new file mode 100644 index 000000000..0f7002541 --- /dev/null +++ b/tests/requests/compute/placement_group_tests.rb @@ -0,0 +1,48 @@ +Shindo.tests('Fog::Compute[:aws] | placement group requests', ['aws']) do + @placement_group_format = { + 'requestId' => String, + 'placementGroupSet' => [{ + 'groupName' => String, + 'state' => String, + 'strategy' => String + }] + } + + tests('success') do + tests("#create_placement_group('fog_placement_group', 'cluster')").formats(Aws::Compute::Formats::BASIC) do + pending if Fog.mocking? + Fog::Compute[:aws].create_placement_group('fog_placement_group', 'cluster').body + end + + tests("#describe_placement_groups").formats(@placement_group_format) do + pending if Fog.mocking? + Fog::Compute[:aws].describe_placement_groups.body + end + + tests("#describe_placement_groups('group-name' => 'fog_placement_group)").formats(@placement_group_format) do + pending if Fog.mocking? + Fog::Compute[:aws].describe_placement_groups('group-name' => 'fog_security_group').body + end + + tests("#delete_placement_group('fog_placement_group')").formats(Aws::Compute::Formats::BASIC) do + pending if Fog.mocking? + Fog::Compute[:aws].delete_placement_group('fog_placement_group').body + end + end + + tests('failure') do + pending if Fog.mocking? + + Fog::Compute[:aws].create_placement_group('fog_placement_group', 'cluster') + + tests("duplicate #create_placement_group('fog_placement_group', 'cluster')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_placement_group('fog_placement_group', 'cluster') + end + + tests("#delete_placement_group('not_a_group_name')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].delete_placement_group('not_a_group_name') + end + + Fog::Compute[:aws].delete_placement_group('fog_placement_group') + end +end diff --git a/tests/requests/compute/region_tests.rb b/tests/requests/compute/region_tests.rb new file mode 100644 index 000000000..4a89ca239 --- /dev/null +++ b/tests/requests/compute/region_tests.rb @@ -0,0 +1,52 @@ +Shindo.tests('Fog::Compute[:aws] | region requests', ['aws']) do + + @regions_format = { + 'regionInfo' => [{ + 'regionEndpoint' => String, + 'regionName' => String + }], + 'requestId' => String + } + + tests('success') do + + tests("#describe_regions").formats(@regions_format) do + Fog::Compute[:aws].describe_regions.body + end + + tests("#describe_regions('region-name' => 'us-east-1')").formats(@regions_format) do + Fog::Compute[:aws].describe_regions('region-name' => 'us-east-1').body + end + + tests("#incorrect_region") do + + raises(ArgumentError, "Unknown region: world-antarctica-1") do + Fog::Compute::AWS.new({:aws_access_key_id => 'dummykey', + :aws_secret_access_key => 'dummysecret', + :aws_session_token => 'dummytoken', + :region => 'world-antarctica-1'}) + end + + end + + tests("#unknown_endpoint").formats(@regions_format) do + Fog::Compute::AWS.new({:aws_access_key_id => 'dummykey', + :aws_secret_access_key => 'dummysecret', + :aws_session_token => 'dummytoken', + :region => 'world-antarctica-1', + :endpoint => 'http://aws-clone.example'}).describe_regions.body + end + + tests("#invalid_endpoint") do + raises(Fog::Compute::AWS::InvalidURIError) do + Fog::Compute::AWS.new({:aws_access_key_id => 'dummykey', + :aws_secret_access_key => 'dummysecret', + :aws_session_token => 'dummytoken', + :region => 'world-antarctica-1', + :endpoint => 'aws-clone.example'}) + end + end + + end + +end diff --git a/tests/requests/compute/route_tests.rb b/tests/requests/compute/route_tests.rb new file mode 100644 index 000000000..0df175c7a --- /dev/null +++ b/tests/requests/compute/route_tests.rb @@ -0,0 +1,339 @@ +Shindo.tests('Fog::Compute[:aws] | route table requests', ['aws']) do + + @route_table_format = { + 'routeTable' => [{ + 'routeSet' => [{ + 'destinationCidrBlock' => String, + 'gatewayId' => String, + 'state' => String, + }], + 'tagSet' => Hash, + 'associationSet' => Array, + 'routeTableId' => String, + 'vpcId' => String, + }], + 'requestId' => String + } + + @route_tables_format = { + 'routeTableSet' => [{ + 'associationSet' => [{ + 'routeTableAssociationId' => Fog::Nullable::String, + 'routeTableId' => String, + 'subnetId' => Fog::Nullable::String, + 'main' => Fog::Boolean + }], + 'tagSet' => Hash, + 'routeSet' => [{ + 'destinationCidrBlock' => String, + 'gatewayId' => Fog::Nullable::String, + 'instanceId' => Fog::Nullable::String, + 'instanceOwnerId' => Fog::Nullable::String, + 'networkInterfaceId' => Fog::Nullable::String, + 'state' => String, + 'origin' => String + }], + 'routeTableId' => String, + 'vpcId' => String, + }], + 'requestId' => String + } + + Fog::Compute::AWS::Mock.reset if Fog.mocking? + vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + if !Fog.mocking? + vpc.wait_for { state.eql? "available" } + end + @subnet_id = Fog::Compute[:aws].create_subnet(vpc.id, '10.0.10.0/24').body['subnet']['subnetId'] + @network_interface = Fog::Compute[:aws].create_network_interface(@subnet_id, {"PrivateIpAddress" => "10.0.10.23"}).body + @internet_gateway_id = Fog::Compute[:aws].create_internet_gateway.body['internetGatewaySet'].first['internetGatewayId'] + @alt_internet_gateway_id = Fog::Compute[:aws].create_internet_gateway.body['internetGatewaySet'].first['internetGatewayId'] + @network_interface_id = @network_interface['networkInterface']['networkInterfaceId'] + key_name = 'fog-test-key' + key = Fog::Compute[:aws].key_pairs.create(:name => key_name) + @cidr_block = '10.0.10.0/24' + @destination_cidr_block = '10.0.10.0/23' + @ami = 'ami-79c0ae10' # ubuntu 12.04 daily build 20120728 + + tests('success') do + + # Test create_route_table + # + tests("#create_route_table('#{vpc.id}')").formats(@route_table_format) do + data = Fog::Compute[:aws].create_route_table(vpc.id).body + @route_table_id = data['routeTable'].first['routeTableId'] + data + end + + # Test associate_route_table + # + tests("#associate_route_table('#{@route_table_id}', '#{@subnet_id}')").formats({'requestId'=>String, 'associationId'=>String}) do + data = Fog::Compute[:aws].associate_route_table(@route_table_id, @subnet_id).body + @association_id = data['associationId'] + data + end + + # Tests create_route + # - using internet gateway + # - using instance id + # - using network interface + # + Fog::Compute[:aws].attach_internet_gateway(@internet_gateway_id, vpc.id).body + tests("#create_route('#{@route_table_id}', '#{@destination_cidr_block}', '#{@internet_gateway_id}', 'nil')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, @internet_gateway_id, nil).body + end + + instance = Fog::Compute[:aws].servers.create(:image_id => @ami, :flavor_id => 't1.micro', :key_name => 'fog-test-key', :subnet_id => @subnet_id) + instance.wait_for { state.eql? "running" } + tests("#create_route('#{@route_table_id}', '10.0.10.0/22', 'nil', '#{instance.id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_route(@route_table_id, '10.0.10.0/22', nil, instance.id).body + end + + tests("#create_route('#{@route_table_id}', '10.0.10.0/21', 'nil', 'nil', '#{@network_interface_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_route(@route_table_id, '10.0.10.0/21', nil, nil, @network_interface_id).body + end + + # Tests replace_route + # - using internet gateway + # - using instance id + # - using network interface + # + Fog::Compute[:aws].attach_internet_gateway(@alt_internet_gateway_id, vpc.id).body + tests("#replace_route('#{@route_table_id}', '#{@destination_cidr_block}', {'gatewayId' => '#{@alt_internet_gateway_id}'})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].replace_route(@route_table_id, @destination_cidr_block, {'gatewayId' => @alt_internet_gateway_id}).body + end + + instance = Fog::Compute[:aws].servers.create(:image_id => @ami, :flavor_id => 't1.micro', :key_name => 'fog-test-key', :subnet_id => @subnet_id) + instance.wait_for { state.eql? "running" } + tests("#replace_route('#{@route_table_id}', '10.0.10.0/22', {'instanceId' => '#{instance.id}'})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].replace_route(@route_table_id, '10.0.10.0/22', {'instanceId' => instance.id}).body + end + + tests("#replace_route('#{@route_table_id}', '10.0.10.0/21', {'networkInterfaceId' => '#{@network_interface_id}'})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].replace_route(@route_table_id, '10.0.10.0/21', {'networkInterfaceId' => @network_interface_id}).body + end + + # Tests describe_route_tables + # - no parameters + # - filter: vpc-id => vpc_id + # - filter: vpc-id => ['all'] + # + tests('#describe_route_tables').formats(@route_tables_format) do + Fog::Compute[:aws].describe_route_tables.body + end + tests("#describe_route_tables('vpc-id' => #{vpc.id})").formats(@route_tables_format) do + Fog::Compute[:aws].describe_route_tables('vpc-id' => vpc.id).body + end + tests("#describe_route_tables('vpc-id' => ['all'])").formats(@route_tables_format) do + Fog::Compute[:aws].describe_route_tables('vpc-id' => ['all']).body + end + + # Test delete_route(route_table_id, cidr_block) + # + tests("#delete_route('#{@route_table_id}', '10.0.10.0/21')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_route(@route_table_id, '10.0.10.0/21').body + end + tests("#delete_route('#{@route_table_id}', '10.0.10.0/22')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_route(@route_table_id, '10.0.10.0/22').body + end + + Fog::Compute[:aws].servers.all('instance-id'=>instance.id).first.destroy + if !Fog.mocking? + instance.wait_for { state.eql? "terminated" } + end + tests("#delete_route('#{@route_table_id}', '#{@destination_cidr_block}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_route(@route_table_id, @destination_cidr_block).body + end + + # Test disassociate_route_table(association_id) + # + tests("#disassociate_route_table('#{@association_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].disassociate_route_table(@association_id).body + end + + # Test delete_route_table(route_table_id) + # + tests("#delete_route_table('#{@route_table_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_route_table(@route_table_id).body + end + end + tests('failure') do + + @route_table_id = Fog::Compute[:aws].create_route_table(vpc.id).body['routeTable'].first['routeTableId'] + @association_id = Fog::Compute[:aws].associate_route_table(@route_table_id, @subnet_id).body['associationId'] + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, @internet_gateway_id, nil) + instance = Fog::Compute[:aws].servers.create(:image_id => @ami, :flavor_id => 't1.micro', :key_name => 'fog-test-key', :subnet_id => @subnet_id) + instance.wait_for { state.eql? "running" } + + # Tests create_route_table + # - no parameters + # - passing a nonexisting vpc + # + tests('#create_route_table').raises(ArgumentError) do + Fog::Compute[:aws].create_route_table + end + tests("#create_route_table('vpc-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route_table('vpc-00000000') + end + + # Tests associate_route_table + # - no parameters + # - passing a nonexisiting route table + # - passing a nonexisiting subnet + # + tests('#associate_route_table').raises(ArgumentError) do + Fog::Compute[:aws].associate_route_table + end + tests("#associate_route_table('rtb-00000000', '#{@subnet_id}')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].associate_route_table('rtb-00000000', @subnet_id) + end + tests("#associate_route_table('#{@route_table_id}', 'subnet-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].associate_route_table(@route_table_id, 'subnet-00000000') + end + + # Tests create_route + # - no parameters + # - passing a nonexisiting route table and an exisiting internet gateway + # - passing a nonexisiting internet gateway + # - passing a nonexisting route table and an exisiting instance + # - passing a nonexisiting instance + # - passing a nonexsiting route table and an exisiting network interface + # - passing a nonexisiting network interface + # - attempting to add a route at the same destination cidr block as another + # - attempting to add a route at a less specific destination cidr block + # + tests('#create_route').raises(ArgumentError) do + Fog::Compute[:aws].create_route + end + tests("#create_route('rtb-00000000', '#{@destination_cidr_block}', '#{@internet_gateway_id}')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route('rtb-00000000', @destination_cidr_block, @internet_gateway_id) + end + tests("#create_route('#{@route_table_id}', '#{@destination_cidr_block}', 'igw-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, 'igw-00000000') + end + tests("#create_route('rtb-00000000', '#{@destination_cidr_block}', 'nil', '#{instance.id}')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route('rtb-00000000', @destination_cidr_block, instance.id) + end + tests("#create_route('#{@route_table_id}', '#{@destination_cidr_block}', 'nil', 'i-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, nil, 'i-00000000') + end + tests("#create_route('#{@route_table_id}', '#{@destinationCidrBlock}', 'nil', 'nil', 'eni-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, nil, nil, 'eni-00000000') + end + tests("#create_route('#rtb-00000000', '#{@destination_cidr_block}', 'nil, 'nil', '#{@network_interface_id}')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_route('rtb-00000000', @destination_cidr_block, nil, nil, @network_interface_id) + end + tests("#create_route same destination_cidr_block").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, @internet_gateway_id) + Fog::Compute[:aws].create_route(@route_table_id, @destination_cidr_block, nil, nil, @network_interface_id).body + end + if !Fog.mocking? + tests("#create_route less specific destination_cidr_block").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_route(@route_table_id, '10.0.10.0/25', @internet_gateway_id) + Fog::Compute[:aws].delete_route(@route_table_id, @destination_cidr_block).body + end + end + + # Tests replace_route + # - no parameters + # - passing a nonexisiting route table and an exisiting internet gateway + # - passing a nonexisiting route table + # - passing a nonexisting route table and an exisiting instance + # - passing a nonexisiting instance + # - passing a nonexsiting route table and an exisiting network interface + # - passing a nonexisiting network interface + # - attempting to add a route at a less specific destination cidr block + # + tests('#replace_route').raises(ArgumentError) do + Fog::Compute[:aws].replace_route + end + tests("#replace_route('rtb-00000000', '#{@destination_cidr_block}', {'internetGatewayId' => '#{@internet_gateway_id}'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route('rtb-00000000', @destination_cidr_block, {'internetGatewayId' => @internet_gateway_id}) + end + tests("#replace_route('rtb-00000000', '#{@destination_cidr_block}')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route('rtb-00000000', @destination_cidr_block) + end + tests("#replace_route('#{@route_table_id}', '#{@destination_cidr_block}', {'gatewayId' => 'igw-00000000'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route(@route_table_id, @destination_cidr_block, {'gatewayId' => 'igw-00000000'}) + end + tests("#replace_route('rtb-00000000', '#{@destination_cidr_block}', {'instanceId' => '#{instance.id}'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route('rtb-00000000', @destination_cidr_block, {'instanceId' => instance.id}) + end + tests("#replace_route('#{@route_table_id}', '#{@destination_cidr_block}', {'instanceId' => 'i-00000000'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route(@route_table_id, @destination_cidr_block, {'instanceId' => 'i-00000000'}) + end + tests("#replace_route('#{@route_table_id}', '#{@destination_cidr_block}', {'networkInterfaceId' => 'eni-00000000'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route(@route_table_id, @destination_cidr_block, {'networkInterfaceId' => 'eni-00000000'}) + end + tests("#replace_route('rtb-00000000', '#{@destination_cidr_block}', {'networkInterfaceId' => '#{@network_interface_id}'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].replace_route('rtb-00000000', @destination_cidr_block, {'networkInterfaceId' => @network_interface_id}) + end + if !Fog.mocking? + tests("#replace_route less specific destination_cidr_block").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].replace_route(@route_table_id, '10.0.10.0/25', {'gatewayId' => @internet_gateway_id}) + end + end + + # Test describe_route_tables + # - passing a nonexisiting vpc + # + tests("#describe_route_tables('vpc-id' => 'vpc-00000000").formats({'routeTableSet'=>Array, 'requestId'=>String}) do + Fog::Compute[:aws].describe_route_tables('vpc-id' => 'vpc-00000000').body + end + + # Tests delete_route + # - no parameters + # - passing a nonexisiting route table + # + tests('#delete_route').raises(ArgumentError) do + Fog::Compute[:aws].delete_route + end + tests("#delete_route('rtb-00000000', '#{@destination_cidr_block}')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].delete_route('rtb-00000000', @destination_cidr_block) + end + + # Tests disassociate_route_table + # - no parameters + # - passing a nonexisiting route table association id + # + tests('#disassociate_route_table').raises(ArgumentError) do + Fog::Compute[:aws].disassociate_route_table + end + tests("#disassociate_route_table('rtbassoc-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].disassociate_route_table('rtbassoc-00000000') + end + + # Tests delete_route_table + # - no parameters + # - passing a nonexisiting route table + # + tests('#delete_route_table').raises(ArgumentError) do + Fog::Compute[:aws].delete_route_table + end + tests("#delete_route_table('rtb-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].delete_route_table('rtb-00000000') + end + + # Dependency Tests + # - route is depending on route_table, so route_table cannot be deleted + # + tests("#delete_route_table('#{@route_table_id}')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].delete_route_table(@route_table_id) + end + + Fog::Compute[:aws].servers.all('instance-id'=>instance.id).first.destroy + if !Fog.mocking? + instance.wait_for { state.eql? "terminated" } + end + Fog::Compute[:aws].delete_route(@route_table_id, @destination_cidr_block) + Fog::Compute[:aws].disassociate_route_table(@association_id) + Fog::Compute[:aws].delete_route_table(@route_table_id) + end + + Fog::Compute[:aws].delete_network_interface(@network_interface_id) + Fog::Compute[:aws].detach_internet_gateway(@internet_gateway_id, vpc.id) + Fog::Compute[:aws].delete_internet_gateway(@internet_gateway_id) + Fog::Compute[:aws].delete_subnet(@subnet_id) + vpc.destroy + key.destroy +end diff --git a/tests/requests/compute/security_group_tests.rb b/tests/requests/compute/security_group_tests.rb new file mode 100644 index 000000000..488729d60 --- /dev/null +++ b/tests/requests/compute/security_group_tests.rb @@ -0,0 +1,437 @@ +Shindo.tests('Fog::Compute[:aws] | security group requests', ['aws']) do + # See https://github.com/fog/fog/issues/2932hj0 + pending + + @create_security_group_format = { + 'requestId' => String, + 'groupId' => String, + 'return' => Fog::Boolean + } + + @security_groups_format = { + 'requestId' => String, + 'securityGroupInfo' => [{ + 'groupDescription' => String, + 'groupId' => Fog::Nullable::String, + 'groupName' => String, + 'ipPermissions' => [{ + 'fromPort' => Fog::Nullable::Integer, + 'groups' => [{ 'groupName' => Fog::Nullable::String, 'userId' => String, 'groupId' => String }], + 'ipProtocol' => String, + 'ipRanges' => [Fog::Nullable::Hash], + 'toPort' => Fog::Nullable::Integer, + }], + 'ipPermissionsEgress' => [], + 'ownerId' => String, + 'vpcId' => Fog::Nullable::String + }] + } + + @owner_id = Fog::Compute[:aws].describe_security_groups('group-name' => 'default').body['securityGroupInfo'].first['ownerId'] + @group_id_default = Fog::Compute[:aws].describe_security_groups('group-name' => 'default').body['securityGroupInfo'].first['groupId'] + + tests('success') do + + tests("#create_security_group('fog_security_group', 'tests group')").formats(@create_security_group_format) do + Fog::Compute[:aws].create_security_group('fog_security_group', 'tests group').body + end + tests("#create_security_group('fog_security_group_two', 'tests group')").formats(@create_security_group_format) do + Fog::Compute[:aws].create_security_group('fog_security_group_two', 'tests group').body + end + @group_id_two = Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group_two').body['securityGroupInfo'].first['groupId'] + group_id = Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['groupId'] + to_be_revoked = [] + expected_permissions = [] + + permission = { 'SourceSecurityGroupName' => 'default' } + tests("#authorize_security_group_ingress('fog_security_group', #{permission.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permission).body + end + + to_be_revoked.push([permission, expected_permissions.dup]) + + expected_permissions = [ + {"groups"=>[{"groupName"=>"default", "userId"=>@owner_id, "groupId"=>@group_id_default}], + "fromPort"=>1, + "ipRanges"=>[], + "ipProtocol"=>"tcp", + "toPort"=>65535}, + {"groups"=>[{"groupName"=>"default", "userId"=>@owner_id, "groupId"=>@group_id_default}], + "fromPort"=>1, + "ipRanges"=>[], + "ipProtocol"=>"udp", + "toPort"=>65535}, + {"groups"=>[{"groupName"=>"default", "userId"=>@owner_id, "groupId"=>@group_id_default}], + "fromPort"=>-1, + "ipRanges"=>[], + "ipProtocol"=>"icmp", + "toPort"=>-1} + ] + + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + tests("#describe_security_groups('group-id' => '#{group_id}')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-id' => group_id).body['securityGroupInfo'].first['ipPermissions']) + end + + permission = { 'SourceSecurityGroupName' => 'fog_security_group_two', 'SourceSecurityGroupOwnerId' => @owner_id } + tests("#authorize_security_group_ingress('fog_security_group', #{permission.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permission).body + end + + to_be_revoked.push([permission, expected_permissions.dup]) + + expected_permissions = [ + {"groups"=> + [{"userId"=>@owner_id, "groupName"=>"default", "groupId"=>@group_id_default}, + {"userId"=>@owner_id, "groupName"=>"fog_security_group_two", "groupId"=>@group_id_two}], + "ipRanges"=>[], + "ipProtocol"=>"tcp", + "fromPort"=>1, + "toPort"=>65535}, + {"groups"=> + [{"userId"=>@owner_id, "groupName"=>"default", "groupId"=>@group_id_default}, + {"userId"=>@owner_id, "groupName"=>"fog_security_group_two", "groupId"=>@group_id_two}], + "ipRanges"=>[], + "ipProtocol"=>"udp", + "fromPort"=>1, + "toPort"=>65535}, + {"groups"=> + [{"userId"=>@owner_id, "groupName"=>"default", "groupId"=>@group_id_default}, + {"userId"=>@owner_id, "groupName"=>"fog_security_group_two", "groupId"=>@group_id_two}], + "ipRanges"=>[], + "ipProtocol"=>"icmp", + "fromPort"=>-1, + "toPort"=>-1} + ] + + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + permission = { 'IpProtocol' => 'tcp', 'FromPort' => '22', 'ToPort' => '22' } + tests("#authorize_security_group_ingress('fog_security_group', #{permission.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permission).body + end + + to_be_revoked.push([permission, expected_permissions.dup]) + + # previous did nothing + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + permission = { 'IpProtocol' => 'tcp', 'FromPort' => '22', 'ToPort' => '22', 'CidrIp' => '10.0.0.0/8' } + tests("#authorize_security_group_ingress('fog_security_group', #{permission.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permission).body + end + + to_be_revoked.push([permission, expected_permissions.dup]) + + expected_permissions += [ + {"groups"=>[], + "ipRanges"=>[{"cidrIp"=>"10.0.0.0/8"}], + "ipProtocol"=>"tcp", + "fromPort"=>22, + "toPort"=>22} + ] + + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + # authorize with nested IpProtocol without IpRanges or Groups does nothing + permissions = { + 'IpPermissions' => [ + { 'IpProtocol' => 'tcp', 'FromPort' => '22', 'ToPort' => '22' } + ] + } + tests("#authorize_security_group_ingress('fog_security_group', #{permissions.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permissions).body + end + + to_be_revoked.push([permissions, expected_permissions.dup]) + + # previous did nothing + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + # authorize with nested IpProtocol with IpRanges + permissions = { + 'IpPermissions' => [ + { + 'IpProtocol' => 'tcp', 'FromPort' => '80', 'ToPort' => '80', + 'IpRanges' => [{ 'CidrIp' => '192.168.0.0/24' }] + } + ] + } + tests("#authorize_security_group_ingress('fog_security_group', #{permissions.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permissions).body + end + + to_be_revoked.push([permissions, expected_permissions.dup]) + + expected_permissions += [ + {"groups"=>[], + "ipRanges"=>[{"cidrIp"=>"192.168.0.0/24"}], + "ipProtocol"=>"tcp", + "fromPort"=>80, + "toPort"=>80} + ] + + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + # authorize with nested IpProtocol with Groups + permissions = { + 'IpPermissions' => [ + { + 'IpProtocol' => 'tcp', 'FromPort' => '8000', 'ToPort' => '8000', + 'Groups' => [{ 'GroupName' => 'fog_security_group_two' }] + } + ] + } + tests("#authorize_security_group_ingress('fog_security_group', #{permissions.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permissions).body + end + + to_be_revoked.push([permissions, expected_permissions.dup]) + + expected_permissions += [ + {"groups"=>[{"userId"=>@owner_id, "groupName"=>"fog_security_group_two", "groupId"=>@group_id_two}], + "ipRanges"=>[], + "ipProtocol"=>"tcp", + "fromPort"=>8000, + "toPort"=>8000} + ] + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + # authorize with nested IpProtocol with IpRanges and Groups + # try integers on this one instead of strings + permissions = { + 'IpPermissions' => [ + { + 'IpProtocol' => 'tcp', 'FromPort' => 9000, 'ToPort' => 9000, + 'IpRanges' => [{ 'CidrIp' => '172.16.0.0/24' }], + 'Groups' => [{ 'GroupName' => 'fog_security_group_two' }] + } + ] + } + tests("#authorize_security_group_ingress('fog_security_group', #{permissions.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', permissions).body + end + + to_be_revoked.push([permissions, expected_permissions.dup]) + + expected_permissions += [ + {"groups"=> + [{"userId"=>@owner_id, "groupName"=>"fog_security_group_two", "groupId"=>@group_id_two}], + "ipRanges"=>[{"cidrIp"=>"172.16.0.0/24"}], + "ipProtocol"=>"tcp", + "fromPort"=>9000, + "toPort"=>9000} + ] + + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + tests("#describe_security_groups").formats(@security_groups_format) do + Fog::Compute[:aws].describe_security_groups.body + end + + tests("#describe_security_groups('group-name' => 'fog_security_group')").formats(@security_groups_format) do + Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body + end + + to_be_revoked.reverse.each do |permission, expected_permissions_after| + tests("#revoke_security_group_ingress('fog_security_group', #{permission.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].revoke_security_group_ingress('fog_security_group', permission).body + end + + tests("#describe_security_groups('group-name' => 'fog_security_group')").returns([]) do + array_differences(expected_permissions_after, Fog::Compute[:aws].describe_security_groups('group-name' => 'fog_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + end + + tests("#delete_security_group('fog_security_group')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_security_group('fog_security_group').body + end + + tests("#delete_security_group('fog_security_group_two')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_security_group('fog_security_group_two').body + end + + vpc_id = Fog::Compute[:aws].create_vpc('10.255.254.64/28').body['vpcSet'].first['vpcId'] + + # Create security group in VPC + tests("#create_security_group('vpc_security_group', 'tests group')").formats(@create_security_group_format) do + Fog::Compute[:aws].create_security_group('vpc_security_group', 'tests group', vpc_id).body + end + + group_id = Fog::Compute[:aws].describe_security_groups('group-name' => 'vpc_security_group').body['securityGroupInfo'].first['groupId'] + + permissions = { + 'IpPermissions' => [ + { + 'IpProtocol' => '42', + 'IpRanges' => [{ 'CidrIp' => '10.0.0.0/8' }], + } + ] + } + + expected_permissions = [ + {"groups"=>[], + "ipRanges"=>[{"cidrIp"=>"10.0.0.0/8"}], + "ipProtocol"=>"42"} + ] + + options = permissions.clone + options['GroupId'] = group_id + tests("#authorize_security_group_ingress(#{options.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress(options).body + end + + tests("#describe_security_groups('group-name' => 'vpc_security_group')").returns([]) do + array_differences(expected_permissions, Fog::Compute[:aws].describe_security_groups('group-name' => 'vpc_security_group').body['securityGroupInfo'].first['ipPermissions']) + end + + tests("#revoke_security_group_ingress(#{options.inspect})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].revoke_security_group_ingress(options).body + end + + vpc_group=Fog::Compute[:aws].security_groups.get_by_id(group_id) + vpc_group.destroy + + Fog::Compute[:aws].delete_vpc(vpc_id) + + end + ## Rate limiting seems to want us to take a break otherwise it will throw errors + tests('failure') do + + @security_group = Fog::Compute[:aws].security_groups.create(:description => 'tests group', :name => 'fog_security_group') + @other_security_group = Fog::Compute[:aws].security_groups.create(:description => 'tests group', :name => 'fog_other_security_group') + + tests("duplicate #create_security_group(#{@security_group.name}, #{@security_group.description})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_security_group(@security_group.name, @security_group.description) + end + + tests("#authorize_security_group_ingress('not_a_group_name', {'FromPort' => 80, 'IpProtocol' => 'tcp', 'toPort' => 80})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].authorize_security_group_ingress( + 'not_a_group_name', + { + 'FromPort' => 80, + 'IpProtocol' => 'tcp', + 'ToPort' => 80, + } + ) + end + + tests("#authorize_security_group_ingress('not_a_group_name', {'SourceSecurityGroupName' => 'not_a_group_name', 'SourceSecurityGroupOwnerId' => '#{@owner_id}'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].authorize_security_group_ingress( + 'not_a_group_name', + { + 'SourceSecurityGroupName' => 'not_a_group_name', + 'SourceSecurityGroupOwnerId' => @owner_id + } + ) + end + + tests("#authorize_security_group_ingress('fog_security_group', {'IpPermissions' => [{'IpProtocol' => 'tcp', 'FromPort' => 80, 'ToPort' => 80, 'IpRanges' => [{'CidrIp' => '10.0.0.0/8'}]}]})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', {'IpPermissions' => [{'IpProtocol' => 'tcp', 'FromPort' => 80, 'ToPort' => 80, 'IpRanges' => [{'CidrIp' => '10.0.0.0/8'}]}]}).body + end + + tests("#authorize_security_group_ingress('fog_security_group', {'IpPermissions' => [{'IpProtocol' => 'tcp', 'FromPort' => 80, 'ToPort' => 80, 'IpRanges' => [{'CidrIp' => '10.0.0.0/8'}]}]})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', {'IpPermissions' => [{'IpProtocol' => 'tcp', 'FromPort' => 80, 'ToPort' => 80, 'IpRanges' => [{'CidrIp' => '10.0.0.0/8'}]}]}) + end + + tests("#authorize_security_group_ingress('fog_security_group', {'IpPermissions' => [{'Groups' => [{'GroupName' => '#{@other_security_group.name}'}], 'FromPort' => 80, 'ToPort' => 80, 'IpProtocol' => 'tcp'}]})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', {'IpPermissions' => [{'Groups' => [{'GroupName' => @other_security_group.name}], 'FromPort' => 80, 'ToPort' => 80, 'IpProtocol' => 'tcp'}]}).body + end + + tests("#delete_security_group('#{@other_security_group.name}')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].delete_security_group(@other_security_group.name) + end + + broken_params = [ + {}, + { "IpProtocol" => "what" }, + { "IpProtocol" => "tcp" }, + { "IpProtocol" => "what", "FromPort" => 1, "ToPort" => 1 }, + ] + broken_params += broken_params.map do |broken_params_item| + { "IpPermissions" => [broken_params_item] } + end + broken_params += [ + { "IpPermissions" => [] }, + { "IpPermissions" => nil } + ] + + broken_params.each do |broken_params_item| + tests("#authorize_security_group_ingress('fog_security_group', #{broken_params_item.inspect})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].authorize_security_group_ingress('fog_security_group', broken_params_item) + end + + tests("#revoke_security_group_ingress('fog_security_group', #{broken_params_item.inspect})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].revoke_security_group_ingress('fog_security_group', broken_params_item) + end + end + + tests("#revoke_security_group_ingress('not_a_group_name', {'FromPort' => 80, 'IpProtocol' => 'tcp', 'toPort' => 80})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].revoke_security_group_ingress( + 'not_a_group_name', + { + 'FromPort' => 80, + 'IpProtocol' => 'tcp', + 'ToPort' => 80, + } + ) + end + + tests("#revoke_security_group_ingress('not_a_group_name', {'SourceSecurityGroupName' => 'not_a_group_name', 'SourceSecurityGroupOwnerId' => '#{@owner_id}'})").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].revoke_security_group_ingress( + 'not_a_group_name', + { + 'SourceSecurityGroupName' => 'not_a_group_name', + 'SourceSecurityGroupOwnerId' => @owner_id + } + ) + end + + tests("#delete_security_group('not_a_group_name')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].delete_security_group('not_a_group_name') + end + + @security_group.destroy + @other_security_group.destroy + + tests("#delete_security_group('default')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].delete_security_group('default') + end + + broken_params = [ + ['fog_security_group', { 'GroupName' => 'fog_security_group' }], + [nil, nil], + [nil, { 'GroupId' => nil }], + [nil, { 'GroupName' => nil, 'GroupId' => nil }] + ] + + broken_params.each do |list_elem| + tests("#authorize_security_group_ingress(#{list_elem[0].inspect}, #{list_elem[1].inspect})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].authorize_security_group_ingress(list_elem[0], list_elem[1]) + end + + tests("#revoke_security_group_ingress(#{list_elem[0].inspect}, #{list_elem[1].inspect})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].revoke_security_group_ingress(list_elem[0], list_elem[1]) + end + end + + end + +end diff --git a/tests/requests/compute/snapshot_tests.rb b/tests/requests/compute/snapshot_tests.rb new file mode 100644 index 000000000..6cd8c7187 --- /dev/null +++ b/tests/requests/compute/snapshot_tests.rb @@ -0,0 +1,77 @@ +Shindo.tests('Fog::Compute[:aws] | snapshot requests', ['aws']) do + + @snapshot_format = { + 'description' => Fog::Nullable::String, + 'encrypted' => Fog::Boolean, + 'ownerId' => String, + 'progress' => String, + 'snapshotId' => String, + 'startTime' => Time, + 'status' => String, + 'volumeId' => String, + 'volumeSize' => Integer + } + + @snapshots_format = { + 'requestId' => String, + 'snapshotSet' => [@snapshot_format.merge('tagSet' => {})] + } + + @snapshot_copy_result = { + 'requestId' => String, + 'snapshotId' => String + } + + @volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1a', :size => 1) + + tests('success') do + + @snapshot_id = nil + + tests("#create_snapshot(#{@volume.identity})").formats(@snapshot_format.merge('progress' => NilClass, 'requestId' => String)) do + data = Fog::Compute[:aws].create_snapshot(@volume.identity).body + @snapshot_id = data['snapshotId'] + data + end + + Fog.wait_for { Fog::Compute[:aws].snapshots.get(@snapshot_id) } + Fog::Compute[:aws].snapshots.get(@snapshot_id).wait_for { ready? } + + tests("#describe_snapshots").formats(@snapshots_format) do + Fog::Compute[:aws].describe_snapshots.body + end + + tests("#describe_snapshots('snapshot-id' => '#{@snapshot_id}')").formats(@snapshots_format) do + Fog::Compute[:aws].describe_snapshots('snapshot-id' => @snapshot_id).body + end + + tests("#copy_snapshot (#{@snapshot_id}, 'us-east-1')").formats(@snapshot_copy_result) do + data = Fog::Compute.new(:provider => :aws, :region => "us-west-1").copy_snapshot(@snapshot_id, "us-east-1").body + @west_snapshot_id = data['snapshotId'] + data + end + + tests("#delete_snapshots(#{@snapshot_id})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_snapshot(@snapshot_id).body + end + + #NOTE: waiting for the copy to complete can sometimes take up to 5 minutes (but sometimes it's nearly instant) + #for faster tests: comment out the rest of this block + Fog.wait_for { Fog::Compute.new(:provider => :aws, :region => "us-west-1").snapshots.get(@west_snapshot_id) } + + tests("#delete_snapshots(#{@west_snapshot_id})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute.new(:provider => :aws, :region => "us-west-1").delete_snapshot(@west_snapshot_id).body + end + + end + tests('failure') do + + tests("#delete_snapshot('snap-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].delete_snapshot('snap-00000000') + end + + end + + @volume.destroy + +end diff --git a/tests/requests/compute/spot_datafeed_subscription_tests.rb b/tests/requests/compute/spot_datafeed_subscription_tests.rb new file mode 100644 index 000000000..25fe7f95c --- /dev/null +++ b/tests/requests/compute/spot_datafeed_subscription_tests.rb @@ -0,0 +1,47 @@ +Shindo.tests('Fog::Compute[:aws] | spot datafeed subscription requests', ['aws']) do + @spot_datafeed_subscription_format = { + 'spotDatafeedSubscription' => { + 'bucket' => String, + 'ownerId' => String, + 'prefix' => String, + 'state' => String + }, + 'requestId' => String + } + + @directory = Fog::Storage[:aws].directories.create(:key => 'fogspotdatafeedsubscriptiontests') + + tests('success') do + pending if Fog.mocking? + + tests("#create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/')").formats(@spot_datafeed_subscription_format) do + Fog::Compute[:aws].create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/').body + end + + tests("duplicate #create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/')").succeeds do + Fog::Compute[:aws].create_spot_datafeed_subscription('fogspotdatafeedsubscriptiontests', 'fogspotdatafeedsubscription/') + end + + tests("#describe_spot_datafeed_subscription").formats(@spot_datafeed_subscription_format) do + Fog::Compute[:aws].describe_spot_datafeed_subscription.body + end + + tests("#delete_spot_datafeed_subscription").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_spot_datafeed_subscription.body + end + + tests("duplicate #delete_spot_datafeed_subscription").succeeds do + Fog::Compute[:aws].delete_spot_datafeed_subscription + end + end + + tests('failure') do + pending if Fog.mocking? + + tests("#describe_spot_datafeed_subscription").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].describe_spot_datafeed_subscription + end + end + + @directory.destroy +end diff --git a/tests/requests/compute/spot_instance_tests.rb b/tests/requests/compute/spot_instance_tests.rb new file mode 100644 index 000000000..9a65fdfcd --- /dev/null +++ b/tests/requests/compute/spot_instance_tests.rb @@ -0,0 +1,57 @@ +Shindo.tests('Fog::Compute[:aws] | spot instance requests', ['aws']) do + + @spot_instance_requests_format = { + 'spotInstanceRequestSet' => [{ + 'createTime' => Time, + 'instanceId' => Fog::Nullable::String, + 'launchedAvailabilityZone' => Fog::Nullable::String, + 'launchSpecification' => { + 'blockDeviceMapping' => [], + 'groupSet' => [String], + 'keyName' => Fog::Nullable::String, + 'imageId' => String, + 'instanceType' => String, + 'monitoring' => Fog::Boolean, + 'ebsOptimized' => Fog::Boolean, + 'subnetId' => Fog::Nullable::String, + 'iamInstanceProfile' => Fog::Nullable::Hash, + }, + 'productDescription' => String, + 'spotInstanceRequestId' => String, + 'spotPrice' => Float, + 'state' => String, + 'type' => String, + 'fault' => Fog::Nullable::Hash, + }], + 'requestId' => String + } + + @cancel_spot_instance_request_format = { + 'spotInstanceRequestSet' => [{ + 'spotInstanceRequestId' => String, + 'state' => String + }], + 'requestId' => String + } + + tests('success') do + + pending if Fog.mocking? + + tests("#request_spot_instances('ami-3202f25b', 't1.micro', '0.001')").formats(@spot_instance_requests_format) do + data = Fog::Compute[:aws].request_spot_instances('ami-3202f25b', 't1.micro', '0.001',{'LaunchSpecification.EbsOptimized' => false}).body + @spot_instance_request_id = data['spotInstanceRequestSet'].first['spotInstanceRequestId'] + data + end + + tests("#describe_spot_instance_requests").formats(@spot_instance_requests_format) do + Fog::Compute[:aws].describe_spot_instance_requests('spot-instance-request-id' => [@spot_instance_request_id]).body + end + + tests("#cancel_spot_instance_requests('#{@spot_instance_request_id}')").formats(@cancel_spot_instance_request_format) do + Fog::Compute[:aws].cancel_spot_instance_requests(@spot_instance_request_id).body + end + + end + +end diff --git a/tests/requests/compute/spot_price_history_tests.rb b/tests/requests/compute/spot_price_history_tests.rb new file mode 100644 index 000000000..d1cf3c543 --- /dev/null +++ b/tests/requests/compute/spot_price_history_tests.rb @@ -0,0 +1,24 @@ +Shindo.tests('Fog::Compute[:aws] | spot price history requests', ['aws']) do + + @spot_price_history_format = { + 'spotPriceHistorySet' => [{ + 'availabilityZone' => String, + 'instanceType' => String, + 'spotPrice' => Float, + 'productDescription' => String, + 'timestamp' => Time + }], + 'requestId' => String + } + + tests('success') do + + pending # Some history data doesn't have an availability zone + + tests("#describe_spot_price_history").formats(@spot_price_history_format) do + Fog::Compute[:aws].describe_spot_price_history.body + end + + end + +end diff --git a/tests/requests/compute/subnet_tests.rb b/tests/requests/compute/subnet_tests.rb new file mode 100644 index 000000000..5e7e9a30a --- /dev/null +++ b/tests/requests/compute/subnet_tests.rb @@ -0,0 +1,85 @@ +Shindo.tests('Fog::Compute[:aws] | subnet requests', ['aws']) do + + @subnet_format = { + 'subnetId' => String, + 'state' => String, + 'vpcId' => String, + 'cidrBlock' => String, + 'availableIpAddressCount' => String, + 'availabilityZone' => String, + 'tagSet' => Hash, + } + + @single_subnet_format = { + 'subnet' => @subnet_format, + 'requestId' => String, + } + + @subnets_format = { + 'subnetSet' => [@subnet_format], + 'requestId' => String + } + + @modify_subnet_format = { + 'requestId' => String, + 'return' => Fog::Boolean + } + + @vpc_network = '10.0.10.0/24' + @vpc=Fog::Compute[:aws].vpcs.create('cidr_block' => @vpc_network) + @vpc_id = @vpc.id + + tests('success') do + @subnet_id = nil + @subnet_network = '10.0.10.16/28' + + tests("#create_subnet('#{@vpc_id}', '#{@subnet_network}')").formats(@single_subnet_format) do + data = Fog::Compute[:aws].create_subnet(@vpc_id, @subnet_network).body + @subnet_id = data['subnet']['subnetId'] + data + end + + tests("modify_subnet('#{@subnet_id}'").formats(@modify_subnet_format) do + Fog::Compute[:aws].modify_subnet_attribute(@subnet_id, 'MapPublicIpOnLaunch' => true).body + end + + @vpc2=Fog::Compute[:aws].vpcs.create('cidr_block' => @vpc_network) + @vpc2_id = @vpc2.id + + # Create a second subnet in a second VPC with the same netblock + tests("#create_subnet('#{@vpc2_id}', '#{@subnet_network}')").formats(@single_subnet_format) do + data = Fog::Compute[:aws].create_subnet(@vpc2_id, @subnet_network).body + @subnet2_id = data['subnet']['subnetId'] + data + end + + Fog::Compute[:aws].delete_subnet(@subnet2_id) + + tests('#describe_subnets').formats(@subnets_format) do + Fog::Compute[:aws].describe_subnets.body + end + + tests("#delete_subnet('#{@subnet_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_subnet(@subnet_id).body + end + end + + tests('failure') do + tests("#create_subnet('vpc-00000000', '10.0.10.0/16')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].create_subnet('vpc-00000000', '10.0.10.0/16') + end + + tests("#create_subnet('#{@vpc_id}', '10.0.9.16/28')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_subnet(@vpc_id, '10.0.9.16/28') + end + + # Attempt to create two subnets with conflicting CIDRs in the same VPC + tests("#create_subnet('#{@vpc_id}', '10.0.10.0/24'); " \ + "#create_subnet('#{@vpc_id}', '10.0.10.64/26'); ").raises(::Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_subnet(@vpc_id, '10.0.10.0/24') + Fog::Compute[:aws].create_subnet(@vpc_id, '10.0.10.64/26') + end + end + + @vpc.destroy +end diff --git a/tests/requests/compute/tag_tests.rb b/tests/requests/compute/tag_tests.rb new file mode 100644 index 000000000..06f18d203 --- /dev/null +++ b/tests/requests/compute/tag_tests.rb @@ -0,0 +1,101 @@ +Shindo.tests('Fog::Compute[:aws] | tag requests', ['aws']) do + Fog::Compute::AWS::Mock.reset if Fog.mocking? + + @tags_format = { + 'tagSet' => [{ + 'key' => String, + 'resourceId' => String, + 'resourceType' => String, + 'value' => Fog::Nullable::String + }], + 'requestId' => String + } + + @volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1a', :size => 1) + @volume.wait_for { ready? } + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => '10.0.10.0/24') + @network_acl = Fog::Compute[:aws].network_acls.all('vpc-id' => @vpc.id, 'default' => true).first + + tests('success') do + if Fog.mocking? + @other_account = Fog::Compute::AWS.new(:aws_access_key_id => 'other', :aws_secret_access_key => 'account') + @image_id = Fog::Compute[:aws].register_image('image', 'image', '/dev/sda1').body['imageId'] + end + + tests("#create_tags('#{@volume.identity}', 'foo' => 'bar')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_tags(@volume.identity, 'foo' => 'bar').body + end + + if Fog.mocking? + tests("#create_tags('#{@image_id}', 'foo' => 'baz')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_tags(@image_id, 'foo' => 'baz').body + end + + tests("#create_tags('#{@vpc.id}', 'type' => 'vpc')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_tags(@vpc.id, 'type' => 'vpc').body + end + + tests("#create_tags('#{@network_acl.network_acl_id}', 'type' => 'network_acl')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].create_tags(@network_acl.network_acl_id, 'type' => 'network_acl').body + end + end + + tests('#describe_tags').formats(@tags_format) do + Fog::Compute[:aws].describe_tags.body + end + + expected_identities = Fog.mocking? ? [@volume.identity, @image_id] : [@volume.identity] + tests('#describe_tags').succeeds do + (expected_identities - Fog::Compute[:aws].describe_tags.body['tagSet'].map {|t| t['resourceId'] }).empty? + end + + tests("#describe_tags('key' => 'foo', 'value' => 'bar')").returns([@volume.identity]) do + Fog::Compute[:aws].describe_tags('key' => 'foo', 'value' => 'bar').body['tagSet'].map {|t| t['resourceId'] } + end + + if Fog.mocking? + tests("#describe_tags('key' => 'foo', 'value' => 'baz')").returns([@image_id]) do + Fog::Compute[:aws].describe_tags('key' => 'foo', 'value' => 'baz').body['tagSet'].map {|t| t['resourceId'] } + end + + Fog::Compute[:aws].modify_image_attribute(@image_id, 'Add.UserId' => [@other_account.data[:owner_id]]) + + tests("other_account#describe_tags('key' => 'foo', 'value' => 'baz')").returns([]) do + @other_account.describe_tags('key' => 'foo', 'value' => 'baz').body['tagSet'].map {|t| t['resourceId'] } + end + + tests("other_account#create_tags('#{@image_id}', 'foo' => 'quux')").formats(Aws::Compute::Formats::BASIC) do + @other_account.create_tags(@image_id, 'foo' => 'quux').body + end + + tests("other_account#describe_tags('key' => 'foo', 'value' => 'quux')").returns([@image_id]) do + @other_account.describe_tags('key' => 'foo', 'value' => 'quux').body['tagSet'].map {|t| t['resourceId'] } + end + end + + @volume.destroy + + tests("#delete_tags('#{@volume.identity}', 'foo' => 'bar')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_tags(@volume.identity, 'foo' => 'bar').body + end + end + + tests('failure') do + tests("#create_tags('vol-00000000', 'baz' => 'qux')").raises(Fog::Service::NotFound) do + Fog::Compute[:aws].create_tags('vol-00000000', 'baz' => 'qux') + end + + tests("#create_tags('abc-12345678', 'type' => 'fake_type')").raises(Fog::Service::NotFound) do + Fog::Compute[:aws].create_tags('abc-12345678', 'type' => 'fake_type') + end + + tests("#create_tags('vpc-12345678', 'type' => 'non-existent_vpc)").raises(Fog::Service::NotFound) do + Fog::Compute[:aws].create_tags('vpc-12345678', 'type' => 'non-existent_vpc') + end + + tests("#create_tags('vpc-123', 'type' => 'bad_resource_id)").raises(Fog::Service::NotFound) do + Fog::Compute[:aws].create_tags('vpc-123', 'type' => 'bad_resource_id') + end + end + Fog::Compute::AWS::Mock.reset if Fog.mocking? +end diff --git a/tests/requests/compute/volume_tests.rb b/tests/requests/compute/volume_tests.rb new file mode 100644 index 000000000..1a3c9edd3 --- /dev/null +++ b/tests/requests/compute/volume_tests.rb @@ -0,0 +1,206 @@ +Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do + + @volume_format = { + 'availabilityZone' => String, + 'createTime' => Time, + 'encrypted' => Fog::Boolean, + 'iops' => Fog::Nullable::Integer, + 'requestId' => String, + 'size' => Integer, + 'snapshotId' => Fog::Nullable::String, + 'status' => String, + 'volumeId' => String, + 'volumeType' => String + } + + @volume_attachment_format = { + 'attachTime' => Time, + 'device' => String, + 'instanceId' => String, + 'requestId' => String, + 'status' => String, + 'volumeId' => String + } + + @volume_status_format = { + 'volumeStatusSet' => [{ + 'availabilityZone' => String, + 'volumeId' => String, + 'volumeStatus' => { + 'status' => String, + 'details' => [{ + 'name' => String, + 'status' => String + }] + }, + 'actionsSet' => [{ + 'code' => String, + 'description' => String, + 'eventId' => String, + 'eventType' => String + }], + 'eventsSet' => [{ + 'description' => String, + 'eventId' => String, + 'eventType' => String, + 'notBefore' => Time, + 'notAfter' => Time + }] + }], + 'requestId' => String + } + + @volumes_format = { + 'volumeSet' => [{ + 'availabilityZone' => String, + 'attachmentSet' => Array, + 'createTime' => Time, + 'encrypted' => Fog::Boolean, + 'iops' => Fog::Nullable::Integer, + 'size' => Integer, + 'snapshotId' => Fog::Nullable::String, + 'status' => String, + 'tagSet' => Hash, + 'volumeId' => String, + 'volumeType' => String + }], + 'requestId' => String + } + + @server = Fog::Compute[:aws].servers.create + @server.wait_for { ready? } + + tests('success') do + @volume_id = nil + + tests('#create_volume').formats(@volume_format) do + data = Fog::Compute[:aws].create_volume(@server.availability_zone, 1).body + @volume_id = data['volumeId'] + data + end + + Fog::Compute[:aws].delete_volume(@volume_id) + + tests('#create_volume from snapshot').formats(@volume_format) do + volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1d', :size => 1) + snapshot = Fog::Compute[:aws].create_snapshot(volume.identity).body + data = Fog::Compute[:aws].create_volume(@server.availability_zone, nil, 'SnapshotId' => snapshot['snapshotId']).body + @volume_id = data['volumeId'] + data + end + + Fog::Compute[:aws].delete_volume(@volume_id) + + tests('#create_volume with type and iops').formats(@volume_format) do + data = Fog::Compute[:aws].create_volume(@server.availability_zone, 10, 'VolumeType' => 'io1', 'Iops' => 100).body + @volume_id = data['volumeId'] + data + end + + Fog::Compute[:aws].delete_volume(@volume_id) + + tests('#create_volume from snapshot with size').formats(@volume_format) do + volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1d', :size => 1) + snapshot = Fog::Compute[:aws].create_snapshot(volume.identity).body + data = Fog::Compute[:aws].create_volume(@server.availability_zone, 1, 'SnapshotId' => snapshot['snapshotId']).body + @volume_id = data['volumeId'] + data + end + + Fog::Compute[:aws].volumes.get(@volume_id).wait_for { ready? } + + tests('#describe_volumes').formats(@volumes_format) do + Fog::Compute[:aws].describe_volumes.body + end + + tests("#describe_volumes('volume-id' => #{@volume_id})").formats(@volumes_format) do + Fog::Compute[:aws].describe_volumes('volume-id' => @volume_id).body + end + + tests("#attach_volume(#{@server.identity}, #{@volume_id}, '/dev/sdh')").formats(@volume_attachment_format) do + Fog::Compute[:aws].attach_volume(@server.identity, @volume_id, '/dev/sdh').body + end + + Fog::Compute[:aws].volumes.get(@volume_id).wait_for { state == 'in-use' } + + tests("#describe_volume('attachment.device' => '/dev/sdh')").formats(@volumes_format) do + Fog::Compute[:aws].describe_volumes('attachment.device' => '/dev/sdh').body + end + + tests("#describe_volume_status('volume-id' => #{@volume_id})").formats(@volume_status_format) do + pending if Fog.mocking? + Fog::Compute[:aws].describe_volume_status('volume-id' => @volume_id).body + end + + tests("#detach_volume('#{@volume_id}')").formats(@volume_attachment_format) do + Fog::Compute[:aws].detach_volume(@volume_id).body + end + + Fog::Compute[:aws].volumes.get(@volume_id).wait_for { ready? } + + tests("#modify_volume_attribute('#{@volume_id}', true)").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].modify_volume_attribute(@volume_id, true).body + end + + tests("#delete_volume('#{@volume_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_volume(@volume_id).body + end + end + + tests('failure') do + @volume = Fog::Compute[:aws].volumes.create(:availability_zone => @server.availability_zone, :size => 1) + + tests("#attach_volume('i-00000000', '#{@volume.identity}', '/dev/sdh')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].attach_volume('i-00000000', @volume.identity, '/dev/sdh') + end + + tests("#attach_volume('#{@server.identity}', 'vol-00000000', '/dev/sdh')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].attach_volume(@server.identity, 'vol-00000000', '/dev/sdh') + end + + tests("#detach_volume('vol-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].detach_volume('vol-00000000') + end + + tests("#modify_volume_attribute('vol-00000000', true)").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].modify_volume_attribute('vol-00000000', true) + end + + tests("#detach_volume('#{@volume.identity}')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].detach_volume(@volume.identity) + end + + tests("#delete_volume('vol-00000000')").raises(Fog::Compute::AWS::NotFound) do + Fog::Compute[:aws].delete_volume('vol-00000000') + end + + # Iops required + tests("#create_volume('#{@server.availability_zone}', 10, 'VolumeType' => 'io1')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_volume(@server.availability_zone, 10, 'VolumeType' => 'io1') + end + + # size too small for iops + tests("#create_volume('#{@server.availability_zone}', 9, 'VolumeType' => 'io1', 'Iops' => 100)").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_volume(@server.availability_zone, 9, 'VolumeType' => 'io1', 'Iops' => 100) + end + + # iops:size ratio too big + tests("#create_volume('#{@server.availability_zone}', 10, 'VolumeType' => 'io1', 'Iops' => 301)").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_volume(@server.availability_zone, 10, 'VolumeType' => 'io1', 'Iops' => 301) + end + + # iops invalid value (lower than 100) + tests("#create_volume('#{@server.availability_zone}', 10, 'VolumeType' => 'io1', 'Iops' => 99)").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_volume(@server.availability_zone, 10, 'VolumeType' => 'io1', 'Iops' => 99) + end + + # iops invalid value (greater than 4000) + tests("#create_volume('#{@server.availability_zone}', 1024, 'VolumeType' => 'io1', 'Iops' => 4001)").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].create_volume(@server.availability_zone, 1024, 'VolumeType' => 'io1', 'Iops' => 4001) + end + + @volume.destroy + end + + @server.destroy +end diff --git a/tests/requests/compute/vpc_tests.rb b/tests/requests/compute/vpc_tests.rb new file mode 100644 index 000000000..5e930e4aa --- /dev/null +++ b/tests/requests/compute/vpc_tests.rb @@ -0,0 +1,111 @@ +Shindo.tests('Fog::Compute[:aws] | vpc requests', ['aws']) do + + @create_vpcs_format = { + 'vpcSet' => [{ + 'vpcId' => String, + 'state' => String, + 'cidrBlock' => String, + 'dhcpOptionsId' => String, + 'tagSet' => Hash + }], + 'requestId' => String + } + + @describe_vpcs_format = { + 'vpcSet' => [{ + 'vpcId' => String, + 'state' => String, + 'cidrBlock' => String, + 'dhcpOptionsId' => String, + 'tagSet' => Hash, + 'instanceTenancy' => Fog::Nullable::String, + }], + 'requestId' => String + } + + tests('success') do + + @vpc_id = nil + + tests('#create_vpc').formats(@create_vpcs_format) do + data = Fog::Compute[:aws].create_vpc('10.255.254.0/28').body + @vpc_id = data['vpcSet'].first['vpcId'] + data + end + + tests('#describe_vpcs').formats(@describe_vpcs_format) do + Fog::Compute[:aws].describe_vpcs.body + end + + [ 'enableDnsSupport', 'enableDnsHostnames'].each do |attrib| + tests("#describe_vpc_attribute('#{@vpc_id}', #{attrib})").returns(@vpc_id) do + Fog::Compute[:aws].describe_vpc_attribute(@vpc_id, attrib).body['vpcId'] + end + end + + tests("#modify_vpc_attribute('#{@vpc_id}', {'EnableDnsSupport.Value' => false})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].modify_vpc_attribute(@vpc_id, {'EnableDnsSupport.Value' => false}).body + end + tests("#describe_vpc_attribute(#{@vpc_id}, 'enableDnsSupport')").returns(false) do + Fog::Compute[:aws].describe_vpc_attribute(@vpc_id, 'enableDnsSupport').body["enableDnsSupport"] + end + tests("#modify_vpc_attribute('#{@vpc_id}', {'EnableDnsSupport.Value' => true})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].modify_vpc_attribute(@vpc_id, {'EnableDnsSupport.Value' => true}).body + end + tests("#describe_vpc_attribute(#{@vpc_id}, 'enableDnsSupport')").returns(true) do + Fog::Compute[:aws].describe_vpc_attribute(@vpc_id, 'enableDnsSupport').body["enableDnsSupport"] + end + + tests("#modify_vpc_attribute('#{@vpc_id}', {'EnableDnsHostnames.Value' => true})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].modify_vpc_attribute(@vpc_id, {'EnableDnsHostnames.Value' => true}).body + end + tests("#describe_vpc_attribute(#{@vpc_id}, 'enableDnsHostnames')").returns(true) do + Fog::Compute[:aws].describe_vpc_attribute(@vpc_id, 'enableDnsHostnames').body["enableDnsHostnames"] + end + tests("#modify_vpc_attribute('#{@vpc_id}', {'EnableDnsHostnames.Value' => false})").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].modify_vpc_attribute(@vpc_id, {'EnableDnsHostnames.Value' => false}).body + end + tests("#describe_vpc_attribute(#{@vpc_id}, 'enableDnsHostnames')").returns(false) do + Fog::Compute[:aws].describe_vpc_attribute(@vpc_id, 'enableDnsHostnames').body["enableDnsHostnames"] + end + + tests("#modify_vpc_attribute('#{@vpc_id}')").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].modify_vpc_attribute(@vpc_id).body + end + + tests("#modify_vpc_attribute('#{@vpc_id}', {'EnableDnsSupport.Value' => true, 'EnableDnsHostnames.Value' => true})").raises(Fog::Compute::AWS::Error) do + Fog::Compute[:aws].modify_vpc_attribute(@vpc_id, {'EnableDnsSupport.Value' => true, 'EnableDnsHostnames.Value' => true}).body + end + + # Create another vpc to test tag filters + test_tags = {'foo' => 'bar'} + @another_vpc = Fog::Compute[:aws].vpcs.create :cidr_block => '1.2.3.4/24', :tags => test_tags + + tests("#describe_vpcs('tag-key' => 'foo')").formats(@describe_vpcs_format)do + body = Fog::Compute[:aws].describe_vpcs('tag-key' => 'foo').body + tests("returns 1 vpc").returns(1) { body['vpcSet'].size } + body + end + + tests("#describe_vpcs('tag-value' => 'bar')").formats(@describe_vpcs_format)do + body = Fog::Compute[:aws].describe_vpcs('tag-value' => 'bar').body + tests("returns 1 vpc").returns(1) { body['vpcSet'].size } + body + end + + tests("#describe_vpcs('tag:foo' => 'bar')").formats(@describe_vpcs_format)do + body = Fog::Compute[:aws].describe_vpcs('tag:foo' => 'bar').body + tests("returns 1 vpc").returns(1) { body['vpcSet'].size } + body + end + + tests("#delete_vpc('#{@vpc_id}')").formats(Aws::Compute::Formats::BASIC) do + Fog::Compute[:aws].delete_vpc(@vpc_id).body + end + + # Clean up + Fog::Compute[:aws].delete_tags(@another_vpc.id, test_tags) + @another_vpc.destroy + Fog::Compute::AWS::Mock.reset if Fog.mocking? + end +end diff --git a/tests/requests/data_pipeline/helper.rb b/tests/requests/data_pipeline/helper.rb new file mode 100644 index 000000000..60a23cd18 --- /dev/null +++ b/tests/requests/data_pipeline/helper.rb @@ -0,0 +1,72 @@ +class Aws + module DataPipeline + module Formats + BASIC = { + 'pipelineId' => String, + } + + FIELDS = [ + { + "key" => String, + "refValue" => Fog::Nullable::String, + "stringValue" => Fog::Nullable::String, + } + ] + + LIST_PIPELINES = { + "hasMoreResults" => Fog::Nullable::Boolean, + "marker" => Fog::Nullable::String, + "pipelineIdList" => [ + { + "id" => String, + "name" => String, + } + ] + } + + QUERY_OBJECTS = { + "hasMoreResults" => Fog::Nullable::Boolean, + "marker" => Fog::Nullable::String, + "ids" => Fog::Nullable::Array, + } + + DESCRIBE_OBJECTS = { + "hasMoreResults" => Fog::Nullable::Boolean, + "marker" => Fog::Nullable::String, + "pipelineObjects" => [ + { + 'id' => String, + 'name' => String, + 'fields' => FIELDS, + } + ] + } + + DESCRIBE_PIPELINES = { + "pipelineDescriptionList" => [ + { + "description" => Fog::Nullable::String, + "name" => String, + "pipelineId" => String, + "fields" => FIELDS, + } + ] + } + + PUT_PIPELINE_DEFINITION = { + "errored" => Fog::Boolean, + "validationErrors" => Fog::Nullable::Array, + } + + GET_PIPELINE_DEFINITION = { + "pipelineObjects" => [ + { + "id" => String, + "name" => String, + "fields" => FIELDS, + } + ] + } + end + end +end diff --git a/tests/requests/data_pipeline/pipeline_tests.rb b/tests/requests/data_pipeline/pipeline_tests.rb new file mode 100644 index 000000000..06696fa40 --- /dev/null +++ b/tests/requests/data_pipeline/pipeline_tests.rb @@ -0,0 +1,78 @@ +Shindo.tests('Aws::DataPipeline | pipeline_tests', ['aws', 'data_pipeline']) do + pending if Fog.mocking? + + @pipeline_id = nil + + tests('success') do + tests("#create_pipeline").formats(Aws::DataPipeline::Formats::BASIC) do + unique_id = 'fog-test-pipeline-unique-id' + name = 'fog-test-pipeline-name' + description = 'Fog test pipeline' + + result = Fog::AWS[:data_pipeline].create_pipeline(unique_id, name, description, {}) + @pipeline_id = result['pipelineId'] + result + end + + tests("#list_pipelines").formats(Aws::DataPipeline::Formats::LIST_PIPELINES) do + Fog::AWS[:data_pipeline].list_pipelines() + end + + tests("#describe_pipelines").formats(Aws::DataPipeline::Formats::DESCRIBE_PIPELINES) do + ids = [@pipeline_id] + Fog::AWS[:data_pipeline].describe_pipelines(ids) + end + + tests("#put_pipeline_definition").formats(Aws::DataPipeline::Formats::PUT_PIPELINE_DEFINITION) do + objects = [ + { + "id" => "Nightly", + "type" => "Schedule", + "startDateTime" => Time.now.strftime("%Y-%m-%dT%H:%M:%S"), + "period" => "24 hours", + }, + { + "id" => "Default", + "role" => "role-dumps", + "resourceRole" => "role-dumps-inst", + "schedule" => { "ref" => "Nightly" }, + }, + ] + + Fog::AWS[:data_pipeline].put_pipeline_definition(@pipeline_id, objects) + end + + tests("#activate_pipeline") do + Fog::AWS[:data_pipeline].activate_pipeline(@pipeline_id) + end + + tests("#get_pipeline_definition").formats(Aws::DataPipeline::Formats::GET_PIPELINE_DEFINITION) do + Fog::AWS[:data_pipeline].get_pipeline_definition(@pipeline_id) + end + + tests("#query_objects") do + tests("for COMPONENTs").formats(Aws::DataPipeline::Formats::QUERY_OBJECTS) do + Fog::AWS[:data_pipeline].query_objects(@pipeline_id, 'COMPONENT') + end + + tests("for INSTANCEs").formats(Aws::DataPipeline::Formats::QUERY_OBJECTS) do + Fog::AWS[:data_pipeline].query_objects(@pipeline_id, 'INSTANCE') + end + + tests("for ATTEMPTs").formats(Aws::DataPipeline::Formats::QUERY_OBJECTS) do + Fog::AWS[:data_pipeline].query_objects(@pipeline_id, 'ATTEMPT') + end + end + + tests('#describe_objects').formats(Aws::DataPipeline::Formats::DESCRIBE_OBJECTS) do + attempts = Fog::AWS[:data_pipeline].query_objects(@pipeline_id, 'ATTEMPT') + object_ids = attempts['ids'][0..5] + Fog::AWS[:data_pipeline].describe_objects(@pipeline_id, object_ids) + end + + tests("#delete_pipeline").returns(true) do + Fog::AWS[:data_pipeline].delete_pipeline(@pipeline_id) + end + + end +end diff --git a/tests/requests/dns/dns_tests.rb b/tests/requests/dns/dns_tests.rb new file mode 100644 index 000000000..7696a6c02 --- /dev/null +++ b/tests/requests/dns/dns_tests.rb @@ -0,0 +1,257 @@ +Shindo.tests('Fog::DNS[:aws] | DNS requests', ['aws', 'dns']) do + + @org_zone_count = 0 + @zone_id = '' + @change_id = '' + @new_records = [] + @domain_name = generate_unique_domain + + @elb_connection = Fog::AWS::ELB.new + @r53_connection = Fog::DNS[:aws] + + tests('success') do + + test('get current zone count') do + @org_zone_count= 0 + response = @r53_connection.list_hosted_zones + if response.status == 200 + @hosted_zones = response.body['HostedZones'] + @org_zone_count = @hosted_zones.count + end + + response.status == 200 + end + + test('create simple zone') { + result = false + + response = @r53_connection.create_hosted_zone(@domain_name) + if response.status == 201 + + zone = response.body['HostedZone'] + change_info = response.body['ChangeInfo'] + ns_servers = response.body['NameServers'] + + if (zone and change_info and ns_servers) + + @zone_id = zone['Id'] + caller_ref = zone['CallerReference'] + @change_id = change_info['Id'] + status = change_info['Status'] + ns_srv_count = ns_servers.count + + if (@zone_id.length > 0) and (caller_ref.length > 0) and (@change_id.length > 0) and + (status.length > 0) and (ns_srv_count > 0) + result = true + end + end + end + + result + } + + test("get status of change #{@change_id}") { + result = false + response = @r53_connection.get_change(@change_id) + if response.status == 200 + status = response.body['Status'] + if (status == 'PENDING') or (status == 'INSYNC') + result = true + end + end + + result + } + + test("get info on hosted zone #{@zone_id}") { + result = false + + response = @r53_connection.get_hosted_zone(@zone_id) + if response.status == 200 + zone = response.body['HostedZone'] + zone_id = zone['Id'] + name = zone['Name'] + caller_ref = zone['CallerReference'] + ns_servers = response.body['NameServers'] + + # Aws returns domain with a dot at end - so when compare, remove dot + if (zone_id == @zone_id) and (name.chop == @domain_name) and (caller_ref.length > 0) and + (ns_servers.count > 0) + result = true + end + end + + result + } + + test('list zones') do + result = false + + response = @r53_connection.list_hosted_zones + if response.status == 200 + + zones= response.body['HostedZones'] + if (zones.count > 0) + zone = zones[0] + zone_id = zone['Id'] + zone_name= zone['Name'] + caller_ref = zone['CallerReference'] + end + max_items = response.body['MaxItems'] + + if (zone_id.length > 0) and (zone_name.length > 0) and (caller_ref.length > 0) and + (max_items > 0) + result = true + end + end + + result + end + + test("add a A resource record") { + # create an A resource record + host = 'www.' + @domain_name + ip_addrs = ['1.2.3.4'] + resource_record = { :name => host, :type => 'A', :ttl => 3600, :resource_records => ip_addrs } + resource_record_set = resource_record.merge(:action => 'CREATE') + + change_batch = [] + change_batch << resource_record_set + options = { :comment => 'add A record to domain'} + response = @r53_connection.change_resource_record_sets(@zone_id, change_batch, options) + if response.status == 200 + change_id = response.body['Id'] + status = response.body['Status'] + @new_records << resource_record + end + + response.status == 200 + } + + test("add a CNAME resource record") { + # create a CNAME resource record + host = 'mail.' + @domain_name + value = ['www.' + @domain_name] + resource_record = { :name => host, :type => 'CNAME', :ttl => 3600, :resource_records => value } + resource_record_set = resource_record.merge(:action => 'CREATE') + + change_batch = [] + change_batch << resource_record_set + options = { :comment => 'add CNAME record to domain'} + response = @r53_connection.change_resource_record_sets( @zone_id, change_batch, options) + if response.status == 200 + change_id = response.body['Id'] + status = response.body['Status'] + @new_records << resource_record + end + + response.status == 200 + } + + test("add a MX resource record") { + # create a MX resource record + host = @domain_name + value = ['7 mail.' + @domain_name] + resource_record = { :name => host, :type => 'MX', :ttl => 3600, :resource_records => value } + resource_record_set = resource_record.merge( :action => 'CREATE') + + change_batch = [] + change_batch << resource_record_set + options = { :comment => 'add MX record to domain'} + response = @r53_connection.change_resource_record_sets( @zone_id, change_batch, options) + if response.status == 200 + change_id = response.body['Id'] + status = response.body['Status'] + @new_records << resource_record + end + + response.status == 200 + } + + test("add an ALIAS resource record") { + # create a load balancer + @elb_connection.create_load_balancer(["us-east-1a"], "fog", [{"Protocol" => "HTTP", "LoadBalancerPort" => "80", "InstancePort" => "80"}]) + + elb_response = @elb_connection.describe_load_balancers("LoadBalancerNames" => "fog") + elb = elb_response.body["DescribeLoadBalancersResult"]["LoadBalancerDescriptions"].first + hosted_zone_id = elb["CanonicalHostedZoneNameID"] + dns_name = elb["DNSName"] + + # create an ALIAS record + host = @domain_name + alias_target = { + :hosted_zone_id => hosted_zone_id, + :dns_name => dns_name, + :evaluate_target_health => false + } + resource_record = { :name => host, :type => 'A', :alias_target => alias_target } + resource_record_set = resource_record.merge(:action => 'CREATE') + + change_batch = [] + change_batch << resource_record_set + options = { :comment => 'add ALIAS record to domain'} + + puts "Hosted Zone ID (ELB): #{hosted_zone_id}" + puts "DNS Name (ELB): #{dns_name}" + puts "Zone ID for Route 53: #{@zone_id}" + + sleep 120 unless Fog.mocking? + response = @r53_connection.change_resource_record_sets(@zone_id, change_batch, options) + if response.status == 200 + change_id = response.body['Id'] + status = response.body['Status'] + @new_records << resource_record + end + + response.status == 200 + } + + tests("list resource records").formats(Aws::DNS::Formats::LIST_RESOURCE_RECORD_SETS) { + # get resource records for zone + @r53_connection.list_resource_record_sets(@zone_id).body + } + + test("delete #{@new_records.count} resource records") { + result = true + + change_batch = [] + @new_records.each { |record| + resource_record_set = record.merge( :action => 'DELETE') + change_batch << resource_record_set + } + options = { :comment => 'remove records from domain'} + response = @r53_connection.change_resource_record_sets(@zone_id, change_batch, options) + if response.status != 200 + result = false + break + end + + result + } + + test("delete hosted zone #{@zone_id}") { + # cleanup the ELB as well + @elb_connection.delete_load_balancer("fog") + + response = @r53_connection.delete_hosted_zone(@zone_id) + + response.status == 200 + } + + end + + tests('failure') do + tests('create hosted zone using invalid domain name').raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + response = @r53_connection.create_hosted_zone('invalid-domain') + end + + tests('get hosted zone using invalid ID').raises(Excon::Errors::NotFound) do + pending if Fog.mocking? + zone_id = 'dummy-id' + response = @r53_connection.get_hosted_zone(zone_id) + end + + end + +end diff --git a/tests/requests/dns/health_check_tests.rb b/tests/requests/dns/health_check_tests.rb new file mode 100644 index 000000000..c7cd31334 --- /dev/null +++ b/tests/requests/dns/health_check_tests.rb @@ -0,0 +1,159 @@ +Shindo.tests('Fog::DNS[:aws] | DNS requests', ['aws', 'dns']) do + + pending if Fog.mocking? + + @r53_connection = Fog::DNS[:aws] + + tests('success') do + + tests('create a health check') do + after do + @r53_connection.delete_health_check(@response.body['HealthCheck']['Id']) + end + + test('create an IP TCP based health check') do + @response = @r53_connection.create_health_check('8.8.8.8', '53', 'TCP') + @response.status == 201 && + @response.body['HealthCheck']['HealthCheckConfig']['IPAddress'] == '8.8.8.8' && + @response.body['HealthCheck']['HealthCheckConfig']['Port'] == '53' + end + + test('create a FQDN HTTP based health check') do + @options = { + :fqdn => "www.amazon.com", + :resource_path => "/gp/cart/view.html/ref=nav_cart" + } + @response = @r53_connection.create_health_check(nil, '80', 'HTTP', @options) + @response.status == 201 && + @response.body['HealthCheck']['HealthCheckConfig']['IPAddress'].nil? && + @response.body['HealthCheck']['HealthCheckConfig']['Port'] == '80' && + @response.body['HealthCheck']['HealthCheckConfig']['FullyQualifiedDomainName'] == 'www.amazon.com' + end + end + + tests('get a health check') do + @options = { + :fqdn => "www.amazon.com", + :resource_path => "/gp/cart/view.html/ref=nav_cart", + :search_string => "Amazon", + :request_interval => 10, + :failure_threshold => "7" + } + create_response = @r53_connection.create_health_check('8.8.8.8', '443', 'HTTPS_STR_MATCH', @options) + @health_check_id = create_response.body['HealthCheck']['Id'] + @response = @r53_connection.get_health_check(@health_check_id) + + sleep 2 + @r53_connection.delete_health_check(@health_check_id) + + test('id') do + @response.body['HealthCheck']['Id'] == @health_check_id + end + + { + 'IPAddress' => '8.8.8.8', + 'Port' => '443', + 'Type' => 'HTTPS_STR_MATCH', + 'FullyQualifiedDomainName' => @options[:fqdn], + 'ResourcePath' => @options[:resource_path], + 'RequestInterval' => @options[:request_interval], + 'FailureThreshold' => @options[:failure_threshold] + }.each do |key, value| + test("and check property #{key}") do + @response.body['HealthCheck']['HealthCheckConfig'][key] == value + end + end + end + + tests('delete a health check') do + before do + response = @r53_connection.create_health_check('8.8.8.8', '53', 'TCP') + @health_check_id = response.body['HealthCheck']['Id'] + end + + test('setup as IP TCP') do + response = @r53_connection.delete_health_check(@health_check_id) + response.status == 200 + end + end + + tests('listing health checks') do + test('succeeds') do + response = @r53_connection.list_health_checks + response.status == 200 + end + + before do + response_1 = @r53_connection.create_health_check('8.8.8.8', '53', 'TCP') + @health_check_1_id = response_1.body['HealthCheck']['Id'] + options = { + :fqdn => "www.amazon.com", + :resource_path => "/gp/cart/view.html/ref=nav_cart" + } + response_2 = @r53_connection.create_health_check(nil, '80', 'HTTP', options) + @health_check_2_id = response_2.body['HealthCheck']['Id'] + @health_check_ids = [@health_check_1_id, @health_check_2_id] + end + + after do + @health_check_ids.each { |id| @r53_connection.delete_health_check id } + end + + test('contains 2 new health checks') do + sleep 2 + response = @r53_connection.list_health_checks + health_checks_by_id = response.body['HealthChecks'].map do |health_check| + health_check['Id'] + end.to_a + @health_check_ids.all? { |id| health_checks_by_id.include?(id) } + end + + test('contains properties') do + sleep 2 + response = @r53_connection.list_health_checks + list_response_2 = response.body['HealthChecks'].find { |health_check| health_check['Id'] == @health_check_2_id } + + list_response_2['HealthCheckConfig']['Type'] == 'HTTP' && + list_response_2['HealthCheckConfig']['FullyQualifiedDomainName'] == 'www.amazon.com' && + list_response_2['HealthCheckConfig']['IPAddress'].nil? + end + end + + tests('assign a health check to a DNS record') do + after do + @r53_connection.change_resource_record_sets(@zone_id, [@resource_record.merge(:action => 'DELETE')]) + @r53_connection.delete_hosted_zone(@zone_id) + @r53_connection.delete_health_check @health_check_id + end + + health_check_response = @r53_connection.create_health_check('8.8.8.8', '53', 'TCP') + raise "Health check was not created" unless health_check_response.status == 201 + @health_check_id = health_check_response.body['HealthCheck']['Id'] + + @domain_name = generate_unique_domain + zone_response = @r53_connection.create_hosted_zone(@domain_name) + raise "Zone was not created for #{@domain_name}" unless zone_response.status == 201 + @zone_id = zone_response.body['HostedZone']['Id'] + + @resource_record = { + :name => "www.#{@domain_name}.", + :type => 'A', + :ttl => 3600, + :resource_records => ['8.8.4.4'], + :health_check_id => @health_check_id, + :set_identifier => SecureRandom.hex(8), + :weight => 50 + } + resource_record_set = [@resource_record.merge(:action => 'CREATE')] + record_response = @r53_connection.change_resource_record_sets @zone_id, resource_record_set + raise "A record was not created" unless record_response.status == 200 + + test('succeeds') do + new_record = @r53_connection.list_resource_record_sets(@zone_id).body['ResourceRecordSets'].find do |record| + record['Name'] == @resource_record[:name] + end + new_record['HealthCheckId'] == @health_check_id + end + end + end +end diff --git a/tests/requests/dns/helper.rb b/tests/requests/dns/helper.rb new file mode 100644 index 000000000..458d38d36 --- /dev/null +++ b/tests/requests/dns/helper.rb @@ -0,0 +1,21 @@ +class Aws + module DNS + module Formats + RESOURCE_RECORD_SET = { + "ResourceRecords" => Array, + "Name" => String, + "Type" => String, + "AliasTarget"=> Fog::Nullable::Hash, + "TTL" => Fog::Nullable::String + } + + LIST_RESOURCE_RECORD_SETS = { + "ResourceRecordSets" => [RESOURCE_RECORD_SET], + "IsTruncated" => Fog::Boolean, + "MaxItems" => Integer, + "NextRecordName" => Fog::Nullable::String, + "NextRecordType" => Fog::Nullable::String + } + end + end +end diff --git a/tests/requests/dynamodb/item_tests.rb b/tests/requests/dynamodb/item_tests.rb new file mode 100644 index 000000000..7acf056d6 --- /dev/null +++ b/tests/requests/dynamodb/item_tests.rb @@ -0,0 +1,137 @@ +Shindo.tests('Fog::AWS[:dynamodb] | item requests', ['aws']) do + + @table_name = "fog_table_#{Time.now.to_f.to_s.gsub('.','')}" + + unless Fog.mocking? + Fog::AWS[:dynamodb].create_table( + @table_name, + {'HashKeyElement' => {'AttributeName' => 'key', 'AttributeType' => 'S'}}, + {'ReadCapacityUnits' => 5, 'WriteCapacityUnits' => 5} + ) + Fog.wait_for { Fog::AWS[:dynamodb].describe_table(@table_name).body['Table']['TableStatus'] == 'ACTIVE' } + end + + tests('success') do + + tests("#put_item('#{@table_name}', {'key' => {'S' => 'key'}}, {'value' => {'S' => 'value'}})").formats('ConsumedCapacityUnits' => Float) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].put_item(@table_name, {'key' => {'S' => 'key'}}, {'value' => {'S' => 'value'}}).body + end + + tests("#update_item('#{@table_name}', {'HashKeyElement' => {'S' => 'key'}}, {'value' => {'Value' => {'S' => 'value'}}})").formats('ConsumedCapacityUnits' => Float) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].update_item(@table_name, {'HashKeyElement' => {'S' => 'key'}}, {'value' => {'Value' => {'S' => 'value'}}}).body + end + + @batch_get_item_format = { + 'Responses' => { + @table_name => { + 'ConsumedCapacityUnits' => Float, + 'Items' => [{ + 'key' => { 'S' => String }, + 'value' => { 'S' => String } + }] + } + }, + 'UnprocessedKeys' => {} + } + + tests("#batch_get_item({'#{@table_name}' => {'Keys' => [{'HashKeyElement' => {'S' => 'key'}}]}})").formats(@batch_get_item_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].batch_get_item( + {@table_name => {'Keys' => [{'HashKeyElement' => {'S' => 'key'}}]}} + ).body + end + + @batch_put_item_format = { + 'Responses'=> { + @table_name => { + 'ConsumedCapacityUnits' => Float} + }, + 'UnprocessedItems'=> {} + } + + tests("#batch_put_item({ '#{@table_name}' => [{ 'PutRequest' => { 'Item' => + { 'HashKeyElement' => { 'S' => 'key' }, 'RangeKeyElement' => { 'S' => 'key' }}}}]})" + ).formats(@batch_put_item_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].batch_put_item( + {@table_name => [{'PutRequest'=> {'Item'=> + {'HashKeyElement' => { 'S' => 'key' }, + 'RangeKeyElement' => { 'S' => 'key' } + }}}]} + ).body + end + + @get_item_format = { + 'ConsumedCapacityUnits' => Float, + 'Item' => { + 'key' => { 'S' => String }, + 'value' => { 'S' => String } + } + } + + tests("#get_item('#{@table_name}', {'HashKeyElement' => {'S' => 'key'}})").formats(@get_item_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].get_item(@table_name, {'HashKeyElement' => {'S' => 'key'}}).body + end + + tests("#get_item('#{@table_name}', {'HashKeyElement' => {'S' => 'notakey'}})").formats('ConsumedCapacityUnits' => Float) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].get_item(@table_name, {'HashKeyElement' => {'S' => 'notakey'}}).body + end + + @query_format = { + 'ConsumedCapacityUnits' => Float, + 'Count' => Integer, + 'Items' => [{ + 'key' => { 'S' => String }, + 'value' => { 'S' => String } + }], + 'LastEvaluatedKey' => NilClass + } + + tests("#query('#{@table_name}', {'S' => 'key'}").formats(@query_format) do + pending if Fog.mocking? + pending # requires a table with range key + Fog::AWS[:dynamodb].query(@table_name, {'S' => 'key'}).body + end + + @scan_format = @query_format.merge('ScannedCount' => Integer) + + tests("scan('#{@table_name}')").formats(@scan_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].scan(@table_name).body + end + + tests("#delete_item('#{@table_name}', {'HashKeyElement' => {'S' => 'key'}})").formats('ConsumedCapacityUnits' => Float) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].delete_item(@table_name, {'HashKeyElement' => {'S' => 'key'}}).body + end + + tests("#delete_item('#{@table_name}, {'HashKeyElement' => {'S' => 'key'}})").formats('ConsumedCapacityUnits' => Float) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].delete_item(@table_name, {'HashKeyElement' => {'S' => 'key'}}).body + end + + end + + tests('failure') do + + tests("#put_item('notatable', {'key' => {'S' => 'key'}}, {'value' => {'S' => 'value'}})").raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].put_item('notatable', {'key' => {'S' => 'key'}}, {'value' => {'S' => 'value'}}) + end + + tests("#update_item('notatable', {'HashKeyElement' => {'S' => 'key'}}, {'value' => {'Value' => {'S' => 'value'}}})").raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].update_item('notatable', {'HashKeyElement' => {'S' => 'key'}}, {'value' => {'Value' => {'S' => 'value'}}}) + end + + end + + unless Fog.mocking? + Fog::AWS[:dynamodb].delete_table(@table_name) + end + +end diff --git a/tests/requests/dynamodb/table_tests.rb b/tests/requests/dynamodb/table_tests.rb new file mode 100644 index 000000000..403d20b89 --- /dev/null +++ b/tests/requests/dynamodb/table_tests.rb @@ -0,0 +1,99 @@ +Shindo.tests('Fog::AWS[:dynamodb] | table requests', ['aws']) do + + @table_format = { + 'CreationDateTime' => Float, + 'KeySchema' => { + 'HashKeyElement' => { + 'AttributeName' => String, + 'AttributeType' => String + } + }, + 'ProvisionedThroughput' => { + 'ReadCapacityUnits' => Integer, + 'WriteCapacityUnits' => Integer + }, + 'TableName' => String, + 'TableStatus' => String + } + + @table_name = "fog_table_#{Time.now.to_f.to_s.gsub('.','')}" + + tests('success') do + + tests("#create_table(#{@table_name}, {'HashKeyElement' => {'AttributeName' => 'id', 'AttributeType' => 'S'}, {'ReadCapacityUnits' => 5, 'WriteCapacityUnits' => 5})").formats('TableDescription' => @table_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].create_table(@table_name, {'HashKeyElement' => {'AttributeName' => 'id', 'AttributeType' => 'S'}}, {'ReadCapacityUnits' => 5, 'WriteCapacityUnits' => 5}).body + end + + tests("#describe_table(#{@table_name})").formats('Table' => @table_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].describe_table(@table_name).body + end + + tests("#list_tables").formats({'LastEvaluatedTableName' => Fog::Nullable::String, 'TableNames' => [String]}) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].list_tables.body + end + + unless Fog.mocking? + Fog.wait_for { Fog::AWS[:dynamodb].describe_table(@table_name).body['Table']['TableStatus'] == 'ACTIVE' } + end + + @update_table_format = { + 'TableDescription' => @table_format.merge({ + 'ItemCount' => Integer, + 'ProvisionedThroughput' => { + 'LastIncreaseDateTime' => Float, + 'ReadCapacityUnits' => Integer, + 'WriteCapacityUnits' => Integer + }, + 'TableSizeBytes' => Integer + }) + } + + tests("#update_table(#{@table_name}, {'ReadCapacityUnits' => 10, 'WriteCapacityUnits' => 10})").formats(@update_table_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].update_table(@table_name, {'ReadCapacityUnits' => 10, 'WriteCapacityUnits' => 10}).body + end + + unless Fog.mocking? + Fog.wait_for { Fog::AWS[:dynamodb].describe_table(@table_name).body['Table']['TableStatus'] == 'ACTIVE' } + end + + @delete_table_format = { + 'TableDescription' => { + 'ProvisionedThroughput' => { + 'ReadCapacityUnits' => Integer, + 'WriteCapacityUnits' => Integer + }, + 'TableName' => String, + 'TableStatus' => String + } + } + + tests("#delete_table(#{@table_name}").formats(@delete_table_format) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].delete_table(@table_name).body + end + + end + + tests('failure') do + + tests("#delete_table('notatable')").raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].delete_table('notatable') + end + + tests("#describe_table('notatable')").raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].describe_table('notatable') + end + + tests("#update_table('notatable', {'ReadCapacityUnits' => 10, 'WriteCapacityUnits' => 10})").raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + Fog::AWS[:dynamodb].update_table('notatable', {'ReadCapacityUnits' => 10, 'WriteCapacityUnits' => 10}).body + end + + end +end diff --git a/tests/requests/elasticache/cache_cluster_tests.rb b/tests/requests/elasticache/cache_cluster_tests.rb new file mode 100644 index 000000000..9ead88af0 --- /dev/null +++ b/tests/requests/elasticache/cache_cluster_tests.rb @@ -0,0 +1,137 @@ +Shindo.tests('Aws::Elasticache | cache cluster requests', ['aws', 'elasticache']) do + + tests('success') do + + # Randomize the cluster ID so tests can be fequently re-run + CLUSTER_ID = "fog-test-cluster-#{rand(999).to_s}" # 20 chars max! + NUM_NODES = 2 # Must be > 1, because one of the tests reomves a node! + + tests( + '#create_cache_cluster' + ).formats(Aws::Elasticache::Formats::SINGLE_CACHE_CLUSTER) do + body = Aws[:elasticache].create_cache_cluster(CLUSTER_ID, + :num_nodes => NUM_NODES + ).body + cluster = body['CacheCluster'] + returns(CLUSTER_ID) { cluster['CacheClusterId'] } + returns('creating') { cluster['CacheClusterStatus'] } + body + end + + tests( + '#describe_cache_clusters without options' + ).formats(Aws::Elasticache::Formats::DESCRIBE_CACHE_CLUSTERS) do + body = Aws[:elasticache].describe_cache_clusters.body + returns(true, "has #{CLUSTER_ID}") do + body['CacheClusters'].any? do |cluster| + cluster['CacheClusterId'] == CLUSTER_ID + end + end + # The DESCRIBE_CACHE_CLUSTERS format must include only one cluster + # So remove all but the relevant cluster from the response body + test_cluster = body['CacheClusters'].delete_if do |cluster| + cluster['CacheClusterId'] != CLUSTER_ID + end + body + end + + tests( + '#describe_cache_clusters with cluster ID' + ).formats(Aws::Elasticache::Formats::DESCRIBE_CACHE_CLUSTERS) do + body = Aws[:elasticache].describe_cache_clusters(CLUSTER_ID).body + returns(1, "size of 1") { body['CacheClusters'].size } + returns(CLUSTER_ID, "has #{CLUSTER_ID}") do + body['CacheClusters'].first['CacheClusterId'] + end + body + end + + Formatador.display_line "Waiting for cluster #{CLUSTER_ID}..." + Aws[:elasticache].clusters.get(CLUSTER_ID).wait_for {ready?} + + tests( + '#describe_cache_clusters with node info' + ).formats(Aws::Elasticache::Formats::CACHE_CLUSTER_RUNNING) do + cluster = Aws[:elasticache].describe_cache_clusters(CLUSTER_ID, + :show_node_info => true + ).body['CacheClusters'].first + returns(NUM_NODES, "has #{NUM_NODES} nodes") do + cluster['CacheNodes'].count + end + cluster + end + + tests( + '#modify_cache_cluster - change a non-pending cluster attribute' + ).formats(Aws::Elasticache::Formats::CACHE_CLUSTER_RUNNING) do + body = Aws[:elasticache].modify_cache_cluster(CLUSTER_ID, + :auto_minor_version_upgrade => false + ).body + # now check that parameter change is in place + returns('false') { body['CacheCluster']['AutoMinorVersionUpgrade'] } + body['CacheCluster'] + end + + tests( + '#reboot_cache_cluster - reboot a node' + ).formats(Aws::Elasticache::Formats::CACHE_CLUSTER_RUNNING) do + c = Aws[:elasticache].clusters.get(CLUSTER_ID) + node_id = c.nodes.last['CacheNodeId'] + Formatador.display_line "Rebooting node #{node_id}..." + body = Aws[:elasticache].reboot_cache_cluster(c.id, [ node_id ]).body + returns('rebooting cache cluster nodes') do + body['CacheCluster']['CacheClusterStatus'] + end + body['CacheCluster'] + end + + Formatador.display_line "Waiting for cluster #{CLUSTER_ID}..." + Aws[:elasticache].clusters.get(CLUSTER_ID).wait_for {ready?} + + tests( + '#modify_cache_cluster - remove a node' + ).formats(Aws::Elasticache::Formats::CACHE_CLUSTER_RUNNING) do + c = Aws[:elasticache].clusters.get(CLUSTER_ID) + node_id = c.nodes.last['CacheNodeId'] + Formatador.display_line "Removing node #{node_id}..." + body = Aws[:elasticache].modify_cache_cluster(c.id, + { + :num_nodes => NUM_NODES - 1, + :nodes_to_remove => [node_id], + :apply_immediately => true, + }).body + returns(node_id) { + body['CacheCluster']['PendingModifiedValues']['CacheNodeId'] + } + body['CacheCluster'] + end + + Formatador.display_line "Waiting for cluster #{CLUSTER_ID}..." + Aws[:elasticache].clusters.get(CLUSTER_ID).wait_for {ready?} + + tests( + '#delete_cache_clusters' + ).formats(Aws::Elasticache::Formats::CACHE_CLUSTER_RUNNING) do + body = Aws[:elasticache].delete_cache_cluster(CLUSTER_ID).body + # make sure this particular cluster is in the returned list + returns(true, "has #{CLUSTER_ID}") do + body['CacheClusters'].any? do |cluster| + cluster['CacheClusterId'] == CLUSTER_ID + end + end + # now check that it reports itself as 'deleting' + cluster = body['CacheClusters'].find do |cluster| + cluster['CacheClusterId'] == CLUSTER_ID + end + returns('deleting') { cluster['CacheClusterStatus'] } + cluster + end + end + + tests('failure') do + # TODO: + # Create a duplicate cluster ID + # List a missing cache cluster + # Delete a missing cache cluster + end +end diff --git a/tests/requests/elasticache/describe_events.rb b/tests/requests/elasticache/describe_events.rb new file mode 100644 index 000000000..c3e5e1041 --- /dev/null +++ b/tests/requests/elasticache/describe_events.rb @@ -0,0 +1,17 @@ +Shindo.tests('Aws::Elasticache | describe cache cluster events', + ['aws', 'elasticache']) do + + tests('success') do + pending if Fog.mocking? + + tests( + '#describe_events' + ).formats(Aws::Elasticache::Formats::EVENT_LIST) do + Aws[:elasticache].describe_events().body['Events'] + end + end + + tests('failure') do + # TODO: + end +end diff --git a/tests/requests/elasticache/describe_reserved_cache_nodes.rb b/tests/requests/elasticache/describe_reserved_cache_nodes.rb new file mode 100644 index 000000000..11795d2d6 --- /dev/null +++ b/tests/requests/elasticache/describe_reserved_cache_nodes.rb @@ -0,0 +1,17 @@ +Shindo.tests('Aws::Elasticache | describe reserved cache nodes', + ['aws', 'elasticache']) do + + tests('success') do + pending if Fog.mocking? + + tests( + '#describe_reserved_cache_nodes' + ).formats(Aws::Elasticache::Formats::RESERVED_CACHE_NODES) do + Aws[:elasticache].describe_reserved_cache_nodes().body['ReservedCacheNodes'] + end + end + + tests('failure') do + # TODO: + end +end diff --git a/tests/requests/elasticache/helper.rb b/tests/requests/elasticache/helper.rb new file mode 100644 index 000000000..f0004914f --- /dev/null +++ b/tests/requests/elasticache/helper.rb @@ -0,0 +1,103 @@ +class Aws + module Elasticache + module Formats + BASIC = { + 'ResponseMetadata' => {'RequestId' => String} + } + + # Cache Security Groups + SECURITY_GROUP = { + 'EC2SecurityGroups' => Array, + 'CacheSecurityGroupName' => String, + 'Description' => String, + 'OwnerId' => String, + } + SINGLE_SECURITY_GROUP = BASIC.merge('CacheSecurityGroup' => SECURITY_GROUP) + DESCRIBE_SECURITY_GROUPS = {'CacheSecurityGroups' => [SECURITY_GROUP]} + + CACHE_SUBNET_GROUP = { + 'CacheSubnetGroupName' => String, + 'CacheSubnetGroupDescription' => String, + 'VpcId' => String, + 'Subnets' => [String] + } + + CREATE_CACHE_SUBNET_GROUP = BASIC.merge({ + 'CreateCacheSubnetGroupResult' => { + 'CacheSubnetGroup' => CACHE_SUBNET_GROUP + } + }) + + DESCRIBE_CACHE_SUBNET_GROUPS = BASIC.merge({ + 'DescribeCacheSubnetGroupsResult' => { + 'CacheSubnetGroups' => [CACHE_SUBNET_GROUP] + } + }) + + # Cache Parameter Groups + PARAMETER_GROUP = { + 'CacheParameterGroupFamily' => String, + 'CacheParameterGroupName' => String, + 'Description' => String, + } + SINGLE_PARAMETER_GROUP = BASIC.merge('CacheParameterGroup' => PARAMETER_GROUP) + DESCRIBE_PARAMETER_GROUPS = BASIC.merge('CacheParameterGroups' => [PARAMETER_GROUP]) + MODIFY_PARAMETER_GROUP = {'CacheParameterGroupName' => String } + PARAMETER_SET = { + 'Parameters' => Array, + 'CacheNodeTypeSpecificParameters' => Array, + } + ENGINE_DEFAULTS = PARAMETER_SET.merge('CacheParameterGroupFamily' => String) + # Cache Clusters - more parameters get added as the lifecycle progresses + CACHE_CLUSTER = { + 'AutoMinorVersionUpgrade' => String, # actually TrueClass or FalseClass + 'CacheSecurityGroups' => Array, + 'CacheClusterId' => String, + 'CacheClusterStatus' => String, + 'CacheNodeType' => String, + 'Engine' => String, + 'EngineVersion' => String, + 'CacheParameterGroup' => Hash, + 'NumCacheNodes' => Integer, + 'PreferredMaintenanceWindow' => String, + 'CacheNodes' => Array, + 'PendingModifiedValues' => Hash, + } + CACHE_CLUSTER_RUNNING = CACHE_CLUSTER.merge({ + 'CacheClusterCreateTime' => DateTime, + 'PreferredAvailabilityZone' => String, + }) + CACHE_CLUSTER_MODIFIED = CACHE_CLUSTER_RUNNING.merge({ + 'NotificationConfiguration' => Hash, + 'PendingModifiedValues' => Hash, + }) + SINGLE_CACHE_CLUSTER = BASIC.merge('CacheCluster' => CACHE_CLUSTER) + DESCRIBE_CACHE_CLUSTERS = BASIC.merge('CacheClusters' => [CACHE_CLUSTER]) + + EVENT = { + 'Date' => DateTime, + 'Message' => String, + 'SourceIdentifier' => String, + 'SourceType' => String, + } + EVENT_LIST = [EVENT] + + RESERVED_CACHE_CLUSTER = { + 'CacheNodeCount' => Integer, + 'CacheNodeType' => String, + 'Duration' => Integer, + 'FixedPrice' => Float, + 'OfferingType' => String, + 'ProductDescription' => String, + 'RecurringCharges' => Array, + 'ReservedCacheNodeId' => String, + 'ReservedCacheNodesOfferingId' => String, + 'StartTime' => DateTime, + 'State' => String, + 'UsagePrice' => Float + } + RESERVED_CACHE_CLUSTER_LIST = [RESERVED_CACHE_CLUSTER] + + end + end +end diff --git a/tests/requests/elasticache/parameter_group_tests.rb b/tests/requests/elasticache/parameter_group_tests.rb new file mode 100644 index 000000000..5b337aa74 --- /dev/null +++ b/tests/requests/elasticache/parameter_group_tests.rb @@ -0,0 +1,105 @@ +Shindo.tests('Aws::Elasticache | parameter group requests', ['aws', 'elasticache']) do + + tests('success') do + pending if Fog.mocking? + + name = 'fog-test' + description = 'Fog Test Parameter Group' + + tests( + '#describe_engine_default_parameters' + ).formats(Aws::Elasticache::Formats::ENGINE_DEFAULTS) do + response = Aws[:elasticache].describe_engine_default_parameters + engine_defaults = response.body['EngineDefaults'] + returns('memcached1.4') { engine_defaults['CacheParameterGroupFamily'] } + engine_defaults + end + + tests( + '#create_cache_parameter_group' + ).formats(Aws::Elasticache::Formats::SINGLE_PARAMETER_GROUP) do + body = Aws[:elasticache].create_cache_parameter_group(name, description).body + group = body['CacheParameterGroup'] + returns(name) { group['CacheParameterGroupName'] } + returns(description) { group['Description'] } + returns('memcached1.4') { group['CacheParameterGroupFamily'] } + body + end + + tests( + '#describe_cache_parameters' + ).formats(Aws::Elasticache::Formats::PARAMETER_SET) do + response = Aws[:elasticache].describe_cache_parameters(name) + parameter_set = response.body['DescribeCacheParametersResult'] + parameter_set + end + + tests( + '#describe_cache_parameter_groups without options' + ).formats(Aws::Elasticache::Formats::DESCRIBE_PARAMETER_GROUPS) do + body = Aws[:elasticache].describe_cache_parameter_groups.body + returns(true, "has #{name}") do + body['CacheParameterGroups'].any? do |group| + group['CacheParameterGroupName'] == name + end + end + body + end + + tests( + '#reset_cache_parameter_group completely' + ).formats('CacheParameterGroupName' => String) do + result = Aws[:elasticache].reset_cache_parameter_group( + name + ).body['ResetCacheParameterGroupResult'] + returns(name) {result['CacheParameterGroupName']} + result + end + + tests( + '#modify_cache_parameter_group' + ).formats('CacheParameterGroupName' => String) do + result = Aws[:elasticache].modify_cache_parameter_group( + name, {"chunk_size" => 32} + ).body['ModifyCacheParameterGroupResult'] + returns(name) {result['CacheParameterGroupName']} + result + end + + # BUG: returns "MalformedInput - Unexpected complex element termination" + tests( + '#reset_cache_parameter_group with one parameter' + ).formats('CacheParameterGroupName' => String) do + pending + result = Aws[:elasticache].reset_cache_parameter_group( + name, ["chunk_size"] + ).body['ResetCacheParameterGroupResult'] + returns(name) {result['CacheParameterGroupName']} + result + end + + tests( + '#describe_cache_parameter_groups with name' + ).formats(Aws::Elasticache::Formats::DESCRIBE_PARAMETER_GROUPS) do + body = Aws[:elasticache].describe_cache_parameter_groups(name).body + returns(1, "size of 1") { body['CacheParameterGroups'].size } + returns(name, "has #{name}") do + body['CacheParameterGroups'].first['CacheParameterGroupName'] + end + body + end + + tests( + '#delete_cache_parameter_group' + ).formats(Aws::Elasticache::Formats::BASIC) do + body = Aws[:elasticache].delete_cache_parameter_group(name).body + end + end + + tests('failure') do + # TODO: + # Create a duplicate parameter group + # List a missing parameter group + # Delete a missing parameter group + end +end diff --git a/tests/requests/elasticache/security_group_tests.rb b/tests/requests/elasticache/security_group_tests.rb new file mode 100644 index 000000000..cc28852a9 --- /dev/null +++ b/tests/requests/elasticache/security_group_tests.rb @@ -0,0 +1,108 @@ +Shindo.tests('Aws::Elasticache | security group requests', ['aws', 'elasticache']) do + + tests('success') do + + name = 'fog-test' + description = 'Fog Test Security Group' + + tests( + '#create_cache_security_group' + ).formats(Aws::Elasticache::Formats::SINGLE_SECURITY_GROUP) do + body = Aws[:elasticache].create_cache_security_group(name, description).body + group = body['CacheSecurityGroup'] + returns(name) { group['CacheSecurityGroupName'] } + returns(description) { group['Description'] } + returns([], "no authorized security group") { group['EC2SecurityGroups'] } + body + end + + tests( + '#describe_cache_security_groups without options' + ).formats(Aws::Elasticache::Formats::DESCRIBE_SECURITY_GROUPS) do + body = Aws[:elasticache].describe_cache_security_groups.body + returns(true, "has #{name}") do + body['CacheSecurityGroups'].any? do |group| + group['CacheSecurityGroupName'] == name + end + end + body + end + + tests( + '#describe_cache_security_groups with name' + ).formats(Aws::Elasticache::Formats::DESCRIBE_SECURITY_GROUPS) do + body = Aws[:elasticache].describe_cache_security_groups(name).body + returns(1, "size of 1") { body['CacheSecurityGroups'].size } + returns(name, "has #{name}") do + body['CacheSecurityGroups'].first['CacheSecurityGroupName'] + end + body + end + + tests('authorization') do + ec2_group = Fog::Compute.new(:provider => 'Aws').security_groups.create( + :name => 'fog-test-elasticache', :description => 'Fog Test Elasticache' + ) + # Reload to get the owner_id + ec2_group.reload + + tests( + '#authorize_cache_security_group_ingress' + ).formats(Aws::Elasticache::Formats::SINGLE_SECURITY_GROUP) do + body = Aws[:elasticache].authorize_cache_security_group_ingress( + name, ec2_group.name, ec2_group.owner_id + ).body + group = body['CacheSecurityGroup'] + expected_ec2_groups = [{ + 'Status' => 'authorizing', 'EC2SecurityGroupName' => ec2_group.name, + 'EC2SecurityGroupOwnerId' => ec2_group.owner_id + }] + returns(expected_ec2_groups, 'has correct EC2 groups') do + group['EC2SecurityGroups'] + end + body + end + + # Wait for the state to be active + Fog.wait_for do + response = Aws[:elasticache].describe_cache_security_groups(name) + group = response.body['CacheSecurityGroups'].first + group['EC2SecurityGroups'].all? {|ec2| ec2['Status'] == 'authorized'} + end + + tests( + '#revoke_cache_security_group_ingress' + ).formats(Aws::Elasticache::Formats::SINGLE_SECURITY_GROUP) do + pending if Fog.mocking? + + body = Aws[:elasticache].revoke_cache_security_group_ingress( + name, ec2_group.name, ec2_group.owner_id + ).body + group = body['CacheSecurityGroup'] + expected_ec2_groups = [{ + 'Status' => 'revoking', 'EC2SecurityGroupName' => ec2_group.name, + 'EC2SecurityGroupOwnerId' => ec2_group.owner_id + }] + returns(expected_ec2_groups, 'has correct EC2 groups') do + group['EC2SecurityGroups'] + end + body + end + + ec2_group.destroy + end + + tests( + '#delete_cache_security_group' + ).formats(Aws::Elasticache::Formats::BASIC) do + body = Aws[:elasticache].delete_cache_security_group(name).body + end + end + + tests('failure') do + # TODO: + # Create a duplicate security group + # List a missing security group + # Delete a missing security group + end +end diff --git a/tests/requests/elasticache/subnet_group_tests.rb b/tests/requests/elasticache/subnet_group_tests.rb new file mode 100644 index 000000000..a37f4da56 --- /dev/null +++ b/tests/requests/elasticache/subnet_group_tests.rb @@ -0,0 +1,52 @@ +Shindo.tests('Aws::Elasticache | subnet group requests', ['aws', 'elasticache']) do + # random_differentiator + # Useful when rapidly re-running tests, so we don't have to wait + # serveral minutes for deleted VPCs/subnets to disappear + suffix = rand(65536).to_s(16) + @subnet_group_name = "fog-test-#{suffix}" + + vpc_range = rand(245) + 10 + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => "10.#{vpc_range}.0.0/16") + + # Create 4 subnets in this VPC, each one in a different AZ + subnet_az = 'us-east-1a' + subnet_range = 8 + @subnets = (1..4).map do + subnet = Fog::Compute[:aws].create_subnet(@vpc.id, "10.#{vpc_range}.#{subnet_range}.0/24", + 'AvailabilityZone' => subnet_az).body['subnet'] + subnet_az = subnet_az.succ + subnet_range *= 2 + subnet + end + + tests('success') do + + subnet_ids = @subnets.map { |sn| sn['subnetId'] }.to_a + + tests("#create_cache_subnet_group").formats(Aws::Elasticache::Formats::CREATE_CACHE_SUBNET_GROUP) do + result = Fog::AWS[:elasticache].create_cache_subnet_group(@subnet_group_name, subnet_ids, 'A subnet group').body + + returns(@subnet_group_name) { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['CacheSubnetGroupName'] } + returns('A subnet group') { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['CacheSubnetGroupDescription'] } + returns(@vpc.id) { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['VpcId'] } + returns(subnet_ids.sort) { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['Subnets'].sort } + + result + end + + tests("#describe_cache_subnet_groups").formats(Aws::Elasticache::Formats::DESCRIBE_CACHE_SUBNET_GROUPS) do + Fog::AWS[:elasticache].describe_cache_subnet_groups.body + end + + tests("#delete_cache_subnet_group").formats(Aws::Elasticache::Formats::BASIC) do + Fog::AWS[:elasticache].delete_cache_subnet_group(@subnet_group_name).body + end + + end + + @subnets.each do |sn| + Fog::Compute[:aws].delete_subnet(sn['subnetId']) + end + @vpc.destroy + +end diff --git a/tests/requests/elb/helper.rb b/tests/requests/elb/helper.rb new file mode 100644 index 000000000..a38237a48 --- /dev/null +++ b/tests/requests/elb/helper.rb @@ -0,0 +1,91 @@ +class Aws + module ELB + module Formats + BASIC = { + 'ResponseMetadata' => {'RequestId' => String} + } + + LOAD_BALANCER = { + "AvailabilityZones" => Array, + "BackendServerDescriptions" => Array, + "CanonicalHostedZoneName" => String, + "CanonicalHostedZoneNameID" => String, + "CreatedTime" => Time, + "DNSName" => String, + "HealthCheck" => {"HealthyThreshold" => Integer, "Timeout" => Integer, "UnhealthyThreshold" => Integer, "Interval" => Integer, "Target" => String}, + "Instances" => Array, + "ListenerDescriptions" => [{ + 'PolicyNames' => Array, + 'Listener' => { + 'InstancePort' => Integer, + 'InstanceProtocol' => String, + 'LoadBalancerPort' => Integer, + 'Protocol' => String, + 'SSLCertificateId' => Fog::Nullable::String + } + }], + "LoadBalancerName" => String, + "Policies" => {"LBCookieStickinessPolicies" => Array, "AppCookieStickinessPolicies" => Array, "OtherPolicies" => Array}, + "Scheme" => String, + "SecurityGroups" => [Fog::Nullable::String], + "SourceSecurityGroup" => {"GroupName" => String, "OwnerAlias" => String}, + "Subnets" => [Fog::Nullable::String] + } + + CREATE_LOAD_BALANCER = BASIC.merge({ + 'CreateLoadBalancerResult' => { 'DNSName' => String } + }) + + DESCRIBE_LOAD_BALANCERS = BASIC.merge({ + 'DescribeLoadBalancersResult' => {'LoadBalancerDescriptions' => [LOAD_BALANCER], 'NextMarker' => Fog::Nullable::String} + }) + + POLICY_ATTRIBUTE_DESCRIPTION = { + "AttributeName" => String, + "AttributeValue" => String + } + + POLICY = { + "PolicyAttributeDescriptions" => [POLICY_ATTRIBUTE_DESCRIPTION], + "PolicyName" => String, + "PolicyTypeName" => String + } + + DESCRIBE_LOAD_BALANCER_POLICIES = BASIC.merge({ + 'DescribeLoadBalancerPoliciesResult' => { 'PolicyDescriptions' => [POLICY] } + }) + + POLICY_ATTRIBUTE_TYPE_DESCRIPTION = { + "AttributeName" => String, + "AttributeType" => String, + "Cardinality" => String, + "DefaultValue" => String, + "Description" => String + } + + POLICY_TYPE = { + "Description" => String, + "PolicyAttributeTypeDescriptions" => [POLICY_ATTRIBUTE_TYPE_DESCRIPTION], + "PolicyTypeName" => String + } + + DESCRIBE_LOAD_BALANCER_POLICY_TYPES = BASIC.merge({ + 'DescribeLoadBalancerPolicyTypesResult' => {'PolicyTypeDescriptions' => [POLICY_TYPE] } + }) + + CONFIGURE_HEALTH_CHECK = BASIC.merge({ + 'ConfigureHealthCheckResult' => {'HealthCheck' => { + 'Target' => String, + 'Interval' => Integer, + 'Timeout' => Integer, + 'UnhealthyThreshold' => Integer, + 'HealthyThreshold' => Integer + }} + }) + + DELETE_LOAD_BALANCER = BASIC.merge({ + 'DeleteLoadBalancerResult' => NilClass + }) + end + end +end diff --git a/tests/requests/elb/listener_tests.rb b/tests/requests/elb/listener_tests.rb new file mode 100644 index 000000000..5203b68e8 --- /dev/null +++ b/tests/requests/elb/listener_tests.rb @@ -0,0 +1,68 @@ +Shindo.tests('Aws::ELB | listener_tests', ['aws', 'elb']) do + @load_balancer_id = 'fog-test-listener' + @key_name = 'fog-test' + + tests('success') do + Fog::AWS[:elb].create_load_balancer(['us-east-1a'], @load_balancer_id, [{'LoadBalancerPort' => 80, 'InstancePort' => 80, 'Protocol' => 'HTTP'}]) + @certificate = Fog::AWS[:iam].upload_server_certificate(Aws::IAM::SERVER_CERT, Aws::IAM::SERVER_CERT_PRIVATE_KEY, @key_name).body['Certificate'] + + tests("#create_load_balancer_listeners").formats(Aws::ELB::Formats::BASIC) do + listeners = [ + {'Protocol' => 'TCP', 'InstanceProtocol' => 'TCP', 'LoadBalancerPort' => 443, 'InstancePort' => 443, 'SSLCertificateId' => @certificate['Arn']}, + {'Protocol' => 'HTTP', 'InstanceProtocol' => 'HTTP', 'LoadBalancerPort' => 80, 'InstancePort' => 80} + ] + response = Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners).body + response + end + + tests("#delete_load_balancer_listeners").formats(Aws::ELB::Formats::BASIC) do + ports = [80, 443] + Fog::AWS[:elb].delete_load_balancer_listeners(@load_balancer_id, ports).body + end + + tests("#create_load_balancer_listeners with non-existant SSL certificate") do + listeners = [ + {'Protocol' => 'HTTPS', 'InstanceProtocol' => 'HTTPS', 'LoadBalancerPort' => 443, 'InstancePort' => 443, 'SSLCertificateId' => 'non-existant'}, + ] + raises(Fog::AWS::IAM::NotFound) { Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners) } + end + + tests("#create_load_balancer_listeners with invalid SSL certificate").raises(Fog::AWS::IAM::NotFound) do + sleep 8 unless Fog.mocking? + listeners = [ + {'Protocol' => 'HTTPS', 'InstanceProtocol' => 'HTTPS', 'LoadBalancerPort' => 443, 'InstancePort' => 443, 'SSLCertificateId' => "#{@certificate['Arn']}fake"}, + ] + Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners).body + end + + # This is sort of fucked up, but it may or may not fail, thanks Aws + tests("#create_load_balancer_listeners with SSL certificate").formats(Aws::ELB::Formats::BASIC) do + sleep 8 unless Fog.mocking? + listeners = [ + {'Protocol' => 'HTTPS', 'InstanceProtocol' => 'HTTPS', 'LoadBalancerPort' => 443, 'InstancePort' => 443, 'SSLCertificateId' => @certificate['Arn']}, + ] + Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners).body + end + + tests("#set_load_balancer_listener_ssl_certificate").formats(Aws::ELB::Formats::BASIC) do + Fog::AWS[:elb].set_load_balancer_listener_ssl_certificate(@load_balancer_id, 443, @certificate['Arn']).body + end + + tests("#create_load_balancer_listeners with invalid Protocol and InstanceProtocol configuration").raises(Fog::AWS::ELB::ValidationError) do + listeners = [ + {'Protocol' => 'HTTP', 'InstanceProtocol' => 'TCP', 'LoadBalancerPort' => 80, 'InstancePort' => 80}, + ] + Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners).body + end + + tests("#create_load_balancer_listeners with valid Protocol and InstanceProtocol configuration").formats(Aws::ELB::Formats::BASIC) do + listeners = [ + {'Protocol' => 'HTTP', 'InstanceProtocol' => 'HTTPS', 'LoadBalancerPort' => 80, 'InstancePort' => 80}, + ] + Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners).body + end + + Fog::AWS[:iam].delete_server_certificate(@key_name) + Fog::AWS[:elb].delete_load_balancer(@load_balancer_id) + end +end diff --git a/tests/requests/elb/load_balancer_tests.rb b/tests/requests/elb/load_balancer_tests.rb new file mode 100644 index 000000000..3f86f915b --- /dev/null +++ b/tests/requests/elb/load_balancer_tests.rb @@ -0,0 +1,89 @@ +Shindo.tests('Aws::ELB | load_balancer_tests', ['aws', 'elb']) do + @load_balancer_id = 'fog-test-elb' + @key_name = 'fog-test' + + tests('success') do + if (Fog::AWS[:iam].get_server_certificate(@key_name) rescue nil) + Fog::AWS[:iam].delete_server_certificate(@key_name) + end + + @certificate = Fog::AWS[:iam].upload_server_certificate(Aws::IAM::SERVER_CERT, Aws::IAM::SERVER_CERT_PRIVATE_KEY, @key_name).body['Certificate'] + + tests("#create_load_balancer").formats(Aws::ELB::Formats::CREATE_LOAD_BALANCER) do + zones = ['us-east-1a'] + listeners = [{'LoadBalancerPort' => 80, 'InstancePort' => 80, 'InstanceProtocol' => 'HTTP', 'Protocol' => 'HTTP'}] + Fog::AWS[:elb].create_load_balancer(zones, @load_balancer_id, listeners).body + end + + tests("#describe_load_balancers").formats(Aws::ELB::Formats::DESCRIBE_LOAD_BALANCERS) do + Fog::AWS[:elb].describe_load_balancers.body + end + + tests('#describe_load_balancers with bad lb') do + raises(Fog::AWS::ELB::NotFound) { Fog::AWS[:elb].describe_load_balancers('LoadBalancerNames' => 'none-such-lb') } + end + + tests("#describe_load_balancers with SSL listener") do + sleep 5 unless Fog.mocking? + listeners = [ + {'Protocol' => 'HTTPS', 'LoadBalancerPort' => 443, 'InstancePort' => 443, 'SSLCertificateId' => @certificate['Arn']}, + ] + Fog::AWS[:elb].create_load_balancer_listeners(@load_balancer_id, listeners) + response = Fog::AWS[:elb].describe_load_balancers('LoadBalancerNames' => @load_balancer_id).body + tests("SSLCertificateId is set").returns(@certificate['Arn']) do + listeners = response["DescribeLoadBalancersResult"]["LoadBalancerDescriptions"].first["ListenerDescriptions"] + listeners.find {|l| l["Listener"]["Protocol"] == 'HTTPS' }["Listener"]["SSLCertificateId"] + end + end + + tests("modify_load_balancer_attributes") do + attributes = { + 'ConnectionDraining' => {'Enabled' => true, 'Timeout' => 600}, + 'CrossZoneLoadBalancing' => {'Enabled' => true}, + 'ConnectionSettings' => {'IdleTimeout' => 180} + } + Fog::AWS[:elb].modify_load_balancer_attributes(@load_balancer_id, attributes).body + response = Fog::AWS[:elb].describe_load_balancer_attributes(@load_balancer_id). + body['DescribeLoadBalancerAttributesResult']['LoadBalancerAttributes'] + + tests("ConnectionDraining is enabled") do + response['ConnectionDraining']['Enabled'] == true + end + tests("ConnectionDraining has a 600 second Timeout").returns(600) do + response['ConnectionDraining']['Timeout'] + end + tests("ConnectionSettings has a 180 second IdleTimeout").returns(180) do + response['ConnectionSettings']['IdleTimeout'] + end + tests("CrossZoneLoadBalancing is enabled") do + response['CrossZoneLoadBalancing']['Enabled'] == true + end + end + + tests("#configure_health_check").formats(Aws::ELB::Formats::CONFIGURE_HEALTH_CHECK) do + health_check = { + 'Target' => 'HTTP:80/index.html', + 'Interval' => 10, + 'Timeout' => 5, + 'UnhealthyThreshold' => 2, + 'HealthyThreshold' => 3 + } + + Fog::AWS[:elb].configure_health_check(@load_balancer_id, health_check).body + end + + tests("#delete_load_balancer").formats(Aws::ELB::Formats::DELETE_LOAD_BALANCER) do + Fog::AWS[:elb].delete_load_balancer(@load_balancer_id).body + end + + tests("#delete_load_balancer when non existant").formats(Aws::ELB::Formats::DELETE_LOAD_BALANCER) do + Fog::AWS[:elb].delete_load_balancer('non-existant').body + end + + tests("#delete_load_balancer when already deleted").formats(Aws::ELB::Formats::DELETE_LOAD_BALANCER) do + Fog::AWS[:elb].delete_load_balancer(@load_balancer_id).body + end + + Fog::AWS[:iam].delete_server_certificate(@key_name) + end +end diff --git a/tests/requests/elb/policy_tests.rb b/tests/requests/elb/policy_tests.rb new file mode 100644 index 000000000..fda4663fd --- /dev/null +++ b/tests/requests/elb/policy_tests.rb @@ -0,0 +1,132 @@ +Shindo.tests('Aws::ELB | policy_tests', ['aws', 'elb']) do + @load_balancer_id = 'fog-test-policies' + + tests('success') do + listeners = [{'LoadBalancerPort' => 80, 'InstancePort' => 80, 'Protocol' => 'HTTP'}] + Fog::AWS[:elb].create_load_balancer(['us-east-1a'], @load_balancer_id, listeners) + + tests("#describe_load_balancer_policy_types").formats(Aws::ELB::Formats::DESCRIBE_LOAD_BALANCER_POLICY_TYPES) do + @policy_types = Fog::AWS[:elb].describe_load_balancer_policy_types.body + end + + tests("#create_app_cookie_stickiness_policy").formats(Aws::ELB::Formats::BASIC) do + cookie, policy = 'fog-app-cookie', 'fog-app-policy' + Fog::AWS[:elb].create_app_cookie_stickiness_policy(@load_balancer_id, policy, cookie).body + end + + tests("#create_lb_cookie_stickiness_policy with expiry").formats(Aws::ELB::Formats::BASIC) do + policy = 'fog-lb-expiry' + expiry = 300 + Fog::AWS[:elb].create_lb_cookie_stickiness_policy(@load_balancer_id, policy, expiry).body + end + + tests("#create_lb_cookie_stickiness_policy without expiry").formats(Aws::ELB::Formats::BASIC) do + policy = 'fog-lb-no-expiry' + Fog::AWS[:elb].create_lb_cookie_stickiness_policy(@load_balancer_id, policy).body + end + + tests("#create_load_balancer_policy").formats(Aws::ELB::Formats::BASIC) do + policy = 'fog-policy' + Fog::AWS[:elb].create_load_balancer_policy(@load_balancer_id, policy, 'PublicKeyPolicyType', {'PublicKey' => Aws::IAM::SERVER_CERT_PUBLIC_KEY}).body + end + + tests("#describe_load_balancer_policies") do + body = Fog::AWS[:elb].describe_load_balancer_policies(@load_balancer_id).body + formats(Aws::ELB::Formats::DESCRIBE_LOAD_BALANCER_POLICIES) { body } + + # Check the result of each policy by name + returns({ + "PolicyAttributeDescriptions"=>[{ + "AttributeName"=>"CookieName", + "AttributeValue"=>"fog-app-cookie" + }], + "PolicyName"=>"fog-app-policy", + "PolicyTypeName"=>"AppCookieStickinessPolicyType" + }) do + body["DescribeLoadBalancerPoliciesResult"]["PolicyDescriptions"].find{|e| e['PolicyName'] == 'fog-app-policy' } + end + + returns({ + "PolicyAttributeDescriptions"=>[{ + "AttributeName"=>"CookieExpirationPeriod", + "AttributeValue"=>"300" + }], + "PolicyName"=>"fog-lb-expiry", + "PolicyTypeName"=>"LBCookieStickinessPolicyType" + }) do + body["DescribeLoadBalancerPoliciesResult"]["PolicyDescriptions"].find{|e| e['PolicyName'] == 'fog-lb-expiry' } + end + + returns({ + "PolicyAttributeDescriptions"=>[{ + "AttributeName"=>"CookieExpirationPeriod", + "AttributeValue"=>"0" + }], + "PolicyName"=>"fog-lb-no-expiry", + "PolicyTypeName"=>"LBCookieStickinessPolicyType" + }) do + body["DescribeLoadBalancerPoliciesResult"]["PolicyDescriptions"].find{|e| e['PolicyName'] == 'fog-lb-no-expiry' } + end + + returns({ + "PolicyAttributeDescriptions"=>[{ + "AttributeName"=>"PublicKey", + "AttributeValue"=> Aws::IAM::SERVER_CERT_PUBLIC_KEY + }], + "PolicyName"=>"fog-policy", + "PolicyTypeName"=>"PublicKeyPolicyType" + }) do + body["DescribeLoadBalancerPoliciesResult"]["PolicyDescriptions"].find{|e| e['PolicyName'] == 'fog-policy' } + end + end + + tests("#describe_load_balancer includes all policies") do + lb = Fog::AWS[:elb].describe_load_balancers("LoadBalancerNames" => [@load_balancer_id]).body["DescribeLoadBalancersResult"]["LoadBalancerDescriptions"].first + returns([ + {"PolicyName"=>"fog-app-policy", "CookieName"=>"fog-app-cookie"} + ]) { lb["Policies"]["AppCookieStickinessPolicies"] } + + returns([ + {"PolicyName"=>"fog-lb-expiry", "CookieExpirationPeriod"=> 300} + ]) { lb["Policies"]["LBCookieStickinessPolicies"].select{|e| e["PolicyName"] == "fog-lb-expiry"} } + + returns([ + {"PolicyName" => "fog-lb-no-expiry"} + ]) { lb["Policies"]["LBCookieStickinessPolicies"].select{|e| e["PolicyName"] == "fog-lb-no-expiry"} } + + returns([ + "fog-policy" + ]) { lb["Policies"]["OtherPolicies"] } + end + + tests("#delete_load_balancer_policy").formats(Aws::ELB::Formats::BASIC) do + policy = 'fog-lb-no-expiry' + Fog::AWS[:elb].delete_load_balancer_policy(@load_balancer_id, policy).body + end + + tests("#set_load_balancer_policies_of_listener adds policy").formats(Aws::ELB::Formats::BASIC) do + port, policies = 80, ['fog-lb-expiry'] + Fog::AWS[:elb].set_load_balancer_policies_of_listener(@load_balancer_id, port, policies).body + end + + tests("#set_load_balancer_policies_of_listener removes policy").formats(Aws::ELB::Formats::BASIC) do + port = 80 + Fog::AWS[:elb].set_load_balancer_policies_of_listener(@load_balancer_id, port, []).body + end + + proxy_policy = "EnableProxyProtocol" + Fog::AWS[:elb].create_load_balancer_policy(@load_balancer_id, proxy_policy, 'ProxyProtocolPolicyType', { "ProxyProtocol" => true }) + + tests("#set_load_balancer_policies_for_backend_server replaces policies on port").formats(Aws::ELB::Formats::BASIC) do + Fog::AWS[:elb].set_load_balancer_policies_for_backend_server(@load_balancer_id, 80, [proxy_policy]).body + end + + tests("#describe_load_balancers has other policies") do + Fog::AWS[:elb].set_load_balancer_policies_for_backend_server(@load_balancer_id, 80, [proxy_policy]).body + description = Fog::AWS[:elb].describe_load_balancers("LoadBalancerNames" => [@load_balancer_id]).body["DescribeLoadBalancersResult"]["LoadBalancerDescriptions"].first + returns(true) { description["Policies"]["OtherPolicies"].include?(proxy_policy) } + end + + Fog::AWS[:elb].delete_load_balancer(@load_balancer_id) + end +end diff --git a/tests/requests/emr/helper.rb b/tests/requests/emr/helper.rb new file mode 100644 index 000000000..74e798907 --- /dev/null +++ b/tests/requests/emr/helper.rb @@ -0,0 +1,168 @@ +class Aws + module EMR + module Formats + BASIC = { + 'RequestId' => String + } + + RUN_JOB_FLOW = BASIC.merge({ + 'JobFlowId' => String + }) + + ADD_INSTANCE_GROUPS = { + 'JobFlowId' => String, + 'InstanceGroupIds' => Array + } + + SIMPLE_DESCRIBE_JOB_FLOW = { + 'JobFlows' => [{ + 'Name' => String, + 'BootstrapActions' => { + 'ScriptBootstrapActionConfig' => { + 'Args' => Array + } + }, + 'ExecutionStatusDetail' => { + 'CreationDateTime' => String, + 'State' => String, + 'LastStateChangeReason' => String + }, + 'Steps' => [{ + 'ActionOnFailure' => String, + 'Name' => String, + 'StepConfig' => { + 'HadoopJarStepConfig' => { + 'MainClass' => String, + 'Jar' => String, + 'Args' => Array, + 'Properties' => Array + } + }, + 'ExecutionStatusDetail' => { + 'CreationDateTime' => String, + 'State' => String + } + }], + 'JobFlowId' => String, + 'Instances' => { + 'InstanceCount' => String, + 'NormalizedInstanceHours' => String, + 'KeepJobFlowAliveWhenNoSteps' => String, + 'Placement' => { + 'AvailabilityZone' => String + }, + 'MasterInstanceType' => String, + 'SlaveInstanceType' => String, + 'InstanceGroups' => Array, + 'TerminationProtected' => String, + 'HadoopVersion' => String + } + }] + } + + JOB_FLOW_WITHOUT_CHANGE = { + 'JobFlows' => [{ + 'Name' => String, + 'BootstrapActions' => { + 'ScriptBootstrapActionConfig' => { + 'Args' => Array + } + }, + 'ExecutionStatusDetail' => { + 'CreationDateTime' => String, + 'State' => String, + 'LastStateChangeReason' => NilClass + }, + 'Steps' => [{ + 'ActionOnFailure' => String, + 'Name' => String, + 'StepConfig' => { + 'HadoopJarStepConfig' => { + 'MainClass' => String, + 'Jar' => String, + 'Args' => Array, + 'Properties' => Array + } + }, + 'ExecutionStatusDetail' => { + 'CreationDateTime' => String, + 'State' => String + } + }], + 'JobFlowId' => String, + 'Instances' => { + 'InstanceCount' => String, + 'NormalizedInstanceHours' => String, + 'KeepJobFlowAliveWhenNoSteps' => String, + 'Placement' => { + 'AvailabilityZone' => String + }, + 'MasterInstanceType' => String, + 'SlaveInstanceType' => String, + 'InstanceGroups' => Array, + 'TerminationProtected' => String, + 'HadoopVersion' => String + } + }] + } + + DESCRIBE_JOB_FLOW_WITH_INSTANCE_GROUPS = { + 'JobFlows' => [{ + 'Name' => String, + 'BootstrapActions' => { + 'ScriptBootstrapActionConfig' => { + 'Args' => Array + } + }, + 'ExecutionStatusDetail' => { + 'CreationDateTime' => String, + 'State' => String, + 'LastStateChangeReason' => NilClass + }, + 'Steps' => [{ + 'ActionOnFailure' => String, + 'Name' => String, + 'StepConfig' => { + 'HadoopJarStepConfig' => { + 'MainClass' => String, + 'Jar' => String, + 'Args' => Array, + 'Properties' => Array + } + }, + 'ExecutionStatusDetail' => { + 'CreationDateTime' => String, + 'State' => String + } + }], + 'JobFlowId' => String, + 'Instances' => { + 'InstanceCount' => String, + 'NormalizedInstanceHours' => String, + 'KeepJobFlowAliveWhenNoSteps' => String, + 'Placement' => { + 'AvailabilityZone' => String + }, + 'InstanceGroups' => [{ + 'Name' => String, + 'InstanceRole' => String, + 'CreationDateTime' => String, + 'LastStateChangeReason' => nil, + 'InstanceGroupId' => String, + 'Market' => String, + 'InstanceType' => String, + 'State' => String, + 'InstanceRunningCount' => String, + 'InstanceRequestCount' => String + }], + 'MasterInstanceType' => String, + 'SlaveInstanceType' => String, + 'InstanceGroups' => Array, + 'TerminationProtected' => String, + 'HadoopVersion' => String + } + }] + } + end + end +end diff --git a/tests/requests/emr/instance_group_tests.rb b/tests/requests/emr/instance_group_tests.rb new file mode 100644 index 000000000..2ed99b195 --- /dev/null +++ b/tests/requests/emr/instance_group_tests.rb @@ -0,0 +1,106 @@ +Shindo.tests('Aws::EMR | instance groups', ['aws', 'emr']) do + + pending if Fog.mocking? + + @job_flow_name = "fog_job_flow_#{Time.now.to_f.to_s.gsub('.','')}" + + @job_flow_options = { + 'Instances' => { + 'MasterInstanceType' => 'm1.small', + 'SlaveInstanceType' => 'm1.small', + 'InstanceCount' => 2, + 'Placement' => { + 'AvailabilityZone' => 'us-east-1a' + }, + 'KeepJobFlowAliveWhenNoSteps' => false, + 'TerminationProtected' => false, + 'HadoopVersion' => '0.20' + } + } + + @job_flow_steps = { + 'Steps' => [{ + 'Name' => 'Dummy streaming job', + 'ActionOnFailure' => 'CONTINUE', + 'HadoopJarStep' => { + 'Jar' => '/home/hadoop/contrib/streaming/hadoop-streaming.jar', + 'MainClass' => nil, + 'Args' => %w(-input s3n://elasticmapreduce/samples/wordcount/input -output hdfs:///examples/output/2011-11-03T090856 -mapper s3n://elasticmapreduce/samples/wordcount/wordSplitter.py -reducer aggregate) + } + }] + } + + @instance_group_name = "fog_instance_group_#{Time.now.to_f.to_s.gsub('.','')}" + @instance_groups = { + 'InstanceGroups' => [{ + 'Name' => @instance_group_name, + 'InstanceRole' => 'TASK', + 'InstanceType' => 'm1.small', + 'InstanceCount' => 2 + }] + } + + result = Aws[:emr].run_job_flow(@job_flow_name, @job_flow_options).body + @job_flow_id = result['JobFlowId'] + + tests('success') do + + tests("#add_instance_groups").formats(Aws::EMR::Formats::ADD_INSTANCE_GROUPS) do + pending if Fog.mocking? + + result = Aws[:emr].add_instance_groups(@job_flow_id, @instance_groups).body + + @instance_group_id = result['InstanceGroupIds'].first + + result + end + + tests("#describe_job_flows_with_instance_groups").formats(Aws::EMR::Formats::DESCRIBE_JOB_FLOW_WITH_INSTANCE_GROUPS) do + pending if Fog.mocking? + + result = Aws[:emr].describe_job_flows('JobFlowIds' => [@job_flow_id]).body + + result + end + + tests("#modify_instance_groups").formats(Aws::EMR::Formats::BASIC) do + pending if Fog.mocking? + + # Add a step so the state doesn't go directly from STARTING to SHUTTING_DOWN + Aws[:emr].add_job_flow_steps(@job_flow_id, @job_flow_steps) + + # Wait until job has started before modifying the instance group + begin + sleep 10 + + result = Aws[:emr].describe_job_flows('JobFlowIds' => [@job_flow_id]).body + job_flow = result['JobFlows'].first + state = job_flow['ExecutionStatusDetail']['State'] + print "." + end while(state == 'STARTING') + + # Check results + result = Aws[:emr].modify_instance_groups('InstanceGroups' => [{'InstanceGroupId' => @instance_group_id, 'InstanceCount' => 4}]).body + + # Check the it actually modified the instance count + tests("modify worked?") do + ig_res = Aws[:emr].describe_job_flows('JobFlowIds' => [@job_flow_id]).body + + matched = false + jf = ig_res['JobFlows'].first + jf['Instances']['InstanceGroups'].each do | ig | + if ig['InstanceGroupId'] == @instance_group_id + matched = true if ig['InstanceRequestCount'].to_i == 4 + end + end + + matched + end + + result + end + + end + + Aws[:emr].terminate_job_flows('JobFlowIds' => [@job_flow_id]) +end diff --git a/tests/requests/emr/job_flow_tests.rb b/tests/requests/emr/job_flow_tests.rb new file mode 100644 index 000000000..4089e8cba --- /dev/null +++ b/tests/requests/emr/job_flow_tests.rb @@ -0,0 +1,88 @@ +Shindo.tests('Aws::EMR | job flows', ['aws', 'emr']) do + + pending if Fog.mocking? + + @job_flow_name = "fog_job_flow_#{Time.now.to_f.to_s.gsub('.','')}" + + @job_flow_options = { + 'Instances' => { + 'MasterInstanceType' => 'm1.small', + 'SlaveInstanceType' => 'm1.small', + 'InstanceCount' => 2, + 'Placement' => { + 'AvailabilityZone' => 'us-east-1a' + }, + 'KeepJobFlowAliveWhenNoSteps' => false, + 'TerminationProtected' => false, + 'HadoopVersion' => '0.20' + } + } + + @step_name = "fog_job_flow_step_#{Time.now.to_f.to_s.gsub('.','')}" + + @job_flow_steps = { + 'Steps' => [{ + 'Name' => @step_name, + 'ActionOnFailure' => 'CONTINUE', + 'HadoopJarStep' => { + 'Jar' => 'FakeJar', + 'MainClass' => 'FakeMainClass', + 'Args' => ['arg1', 'arg2'] + } + }] + } + + @job_flow_id = nil + + tests('success') do + + tests("#run_job_flow").formats(Aws::EMR::Formats::RUN_JOB_FLOW) do + pending if Fog.mocking? + + result = Aws[:emr].run_job_flow(@job_flow_name, @job_flow_options).body + @job_flow_id = result['JobFlowId'] + + result + end + + tests("#add_job_flow_steps").formats(Aws::EMR::Formats::BASIC) do + pending if Fog.mocking? + + result = Aws[:emr].add_job_flow_steps(@job_flow_id, @job_flow_steps).body + + result + end + + tests("#set_termination_protection").formats(Aws::EMR::Formats::BASIC) do + + result = Aws[:emr].set_termination_protection(true, 'JobFlowIds' => [@job_flow_id]).body + + test("protected?") do + res = Aws[:emr].describe_job_flows('JobFlowIds' => [@job_flow_id]).body + jf = res['JobFlows'].first + + jf['Instances']['TerminationProtected'] == 'true' + end + + result + end + + tests("#terminate_job_flow").formats(Aws::EMR::Formats::BASIC) do + pending if Fog.mocking? + Aws[:emr].set_termination_protection(false, 'JobFlowIds' => [@job_flow_id]) + + result = Aws[:emr].terminate_job_flows('JobFlowIds' => [@job_flow_id]).body + + result + end + + tests("#describe_job_flows").formats(Aws::EMR::Formats::SIMPLE_DESCRIBE_JOB_FLOW) do + pending if Fog.mocking? + + result = Aws[:emr].describe_job_flows('JobFlowIds' => [@job_flow_id]).body + + result + end + + end +end diff --git a/tests/requests/glacier/archive_tests.rb b/tests/requests/glacier/archive_tests.rb new file mode 100644 index 000000000..ea4fc59b0 --- /dev/null +++ b/tests/requests/glacier/archive_tests.rb @@ -0,0 +1,13 @@ +Shindo.tests('Aws::Glacier | glacier archive tests', ['aws']) do + pending if Fog.mocking? + + Fog::AWS[:glacier].create_vault('Fog-Test-Vault-upload') + + tests('single part upload') do + id = Fog::AWS[:glacier].create_archive('Fog-Test-Vault-upload', 'data body').headers['x-amz-archive-id'] + Fog::AWS[:glacier].delete_archive('Fog-Test-Vault-upload', id) + end + + #amazon won't let us delete the vault because it has been written to in the past day + +end diff --git a/tests/requests/glacier/multipart_upload_tests.rb b/tests/requests/glacier/multipart_upload_tests.rb new file mode 100644 index 000000000..88456675e --- /dev/null +++ b/tests/requests/glacier/multipart_upload_tests.rb @@ -0,0 +1,29 @@ +Shindo.tests('Aws::Glacier | glacier archive tests', ['aws']) do + pending if Fog.mocking? + + Fog::AWS[:glacier].create_vault('Fog-Test-Vault-upload') + + tests('initiate and abort') do + id = Fog::AWS[:glacier].initiate_multipart_upload('Fog-Test-Vault-upload', 1024*1024).headers['x-amz-multipart-upload-id'] + returns(true){ Fog::AWS[:glacier].list_multipart_uploads('Fog-Test-Vault-upload').body['UploadsList'].map {|item| item['MultipartUploadId']}.include?(id)} + Fog::AWS[:glacier].abort_multipart_upload('Fog-Test-Vault-upload', id) + returns(false){ Fog::AWS[:glacier].list_multipart_uploads('Fog-Test-Vault-upload').body['UploadsList'].map {|item| item['MultipartUploadId']}.include?(id)} + end + + tests('do multipart upload') do + hash = Fog::AWS::Glacier::TreeHash.new + id = Fog::AWS[:glacier].initiate_multipart_upload('Fog-Test-Vault-upload', 1024*1024).headers['x-amz-multipart-upload-id'] + part = 't'*1024*1024 + hash_for_part = hash.add_part(part) + Fog::AWS[:glacier].upload_part('Fog-Test-Vault-upload', id, part, 0, hash_for_part) + + part_2 = 'u'*1024*1024 + hash_for_part_2 = hash.add_part(part_2) + Fog::AWS[:glacier].upload_part('Fog-Test-Vault-upload', id, part_2, 1024*1024, hash_for_part_2) + + archive = Fog::AWS[:glacier].complete_multipart_upload('Fog-Test-Vault-upload', id, 2*1024*1024, hash.hexdigest).headers['x-amz-archive-id'] + + Fog::AWS[:glacier].delete_archive('Fog-Test-Vault-upload', archive) + #amazon won't let us delete the vault because it has been written to in the past day + end +end diff --git a/tests/requests/glacier/tree_hash_tests.rb b/tests/requests/glacier/tree_hash_tests.rb new file mode 100644 index 000000000..6c062ec48 --- /dev/null +++ b/tests/requests/glacier/tree_hash_tests.rb @@ -0,0 +1,62 @@ +Shindo.tests('Aws::Glacier | glacier tree hash calcuation', ['aws']) do + + tests('tree_hash(single part < 1MB)') do + returns(Digest::SHA256.hexdigest('')) { Fog::AWS::Glacier::TreeHash.digest('')} + end + + tests('tree_hash(multibyte characters)') do + body = ("\xC2\xA1" * 1024*1024) + body.force_encoding('UTF-8') if body.respond_to? :encoding + + expected = Digest::SHA256.hexdigest( + Digest::SHA256.digest("\xC2\xA1" * 1024*512) + Digest::SHA256.digest("\xC2\xA1" * 1024*512) + ) + returns(expected) { Fog::AWS::Glacier::TreeHash.digest(body)} + end + + tests('tree_hash(power of 2 number of parts)') do + body = ('x' * 1024*1024) + ('y'*1024*1024) + ('z'*1024*1024) + ('t'*1024*1024) + expected = Digest::SHA256.hexdigest( + Digest::SHA256.digest( + Digest::SHA256.digest('x' * 1024*1024) + Digest::SHA256.digest('y' * 1024*1024) + ) + + Digest::SHA256.digest( + Digest::SHA256.digest('z' * 1024*1024) + Digest::SHA256.digest('t' * 1024*1024) + ) + ) + + returns(expected) { Fog::AWS::Glacier::TreeHash.digest(body)} + end + + tests('tree_hash(non power of 2 number of parts)') do + body = ('x' * 1024*1024) + ('y'*1024*1024) + ('z'*1024*1024) + expected = Digest::SHA256.hexdigest( + Digest::SHA256.digest( + Digest::SHA256.digest('x' * 1024*1024) + Digest::SHA256.digest('y' * 1024*1024) + ) + + Digest::SHA256.digest('z' * 1024*1024) + ) + + returns(expected) { Fog::AWS::Glacier::TreeHash.digest(body)} + end + + tests('multipart') do + tree_hash = Fog::AWS::Glacier::TreeHash.new + part = ('x' * 1024*1024) + ('y'*1024*1024) + returns(Fog::AWS::Glacier::TreeHash.digest(part)) { tree_hash.add_part part } + + tree_hash.add_part('z'* 1024*1024 + 't'*1024*1024) + + expected = Digest::SHA256.hexdigest( + Digest::SHA256.digest( + Digest::SHA256.digest('x' * 1024*1024) + Digest::SHA256.digest('y' * 1024*1024) + ) + + Digest::SHA256.digest( + Digest::SHA256.digest('z' * 1024*1024) + Digest::SHA256.digest('t' * 1024*1024) + ) + ) + returns(expected) { tree_hash.hexdigest} + + end + +end diff --git a/tests/requests/glacier/vault_tests.rb b/tests/requests/glacier/vault_tests.rb new file mode 100644 index 000000000..63373bbc6 --- /dev/null +++ b/tests/requests/glacier/vault_tests.rb @@ -0,0 +1,35 @@ +Shindo.tests('Aws::Glacier | glacier vault requests', ['aws']) do + pending if Fog.mocking? + + topic_arn = Fog::AWS[:sns].create_topic( 'fog_test_glacier_topic').body['TopicArn'] + Fog::AWS[:glacier].create_vault('Fog-Test-Vault') + + tests('list_vaults') do + returns(true){Fog::AWS[:glacier].list_vaults.body['VaultList'].map {|data| data['VaultName']}.include?('Fog-Test-Vault')} + end + + tests('describe_vault') do + returns('Fog-Test-Vault'){Fog::AWS[:glacier].describe_vault('Fog-Test-Vault').body['VaultName']} + end + + tests('set_vault_notification_configuration') do + Fog::AWS[:glacier].set_vault_notification_configuration 'Fog-Test-Vault', topic_arn, ['ArchiveRetrievalCompleted'] + end + + tests('get_vault_notification_configuration') do + returns('SNSTopic' => topic_arn, 'Events' => ['ArchiveRetrievalCompleted']){ Fog::AWS[:glacier].get_vault_notification_configuration( 'Fog-Test-Vault').body} + end + + tests('delete_vault_notification_configuration') do + Fog::AWS[:glacier].delete_vault_notification_configuration( 'Fog-Test-Vault') + raises(Excon::Errors::NotFound){Fog::AWS[:glacier].get_vault_notification_configuration( 'Fog-Test-Vault')} + end + + tests('delete_vault') do + Fog::AWS[:glacier].delete_vault( 'Fog-Test-Vault') + raises(Excon::Errors::NotFound){Fog::AWS[:glacier].describe_vault( 'Fog-Test-Vault')} + end + + Fog::AWS[:sns].delete_topic topic_arn + +end diff --git a/tests/requests/iam/access_key_tests.rb b/tests/requests/iam/access_key_tests.rb new file mode 100644 index 000000000..0e388aa4d --- /dev/null +++ b/tests/requests/iam/access_key_tests.rb @@ -0,0 +1,53 @@ +Shindo.tests('Aws::IAM | access key requests', ['aws']) do + + Fog::AWS[:iam].create_user('fog_access_key_tests') + + tests('success') do + + @access_key_format = { + 'AccessKey' => { + 'AccessKeyId' => String, + 'UserName' => String, + 'SecretAccessKey' => String, + 'Status' => String + }, + 'RequestId' => String + } + + tests("#create_access_key('UserName' => 'fog_access_key_tests')").formats(@access_key_format) do + data = Fog::AWS[:iam].create_access_key('UserName' => 'fog_access_key_tests').body + @access_key_id = data['AccessKey']['AccessKeyId'] + data + end + + @access_keys_format = { + 'AccessKeys' => [{ + 'AccessKeyId' => String, + 'Status' => String + }], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + } + + tests("#list_access_keys('Username' => 'fog_access_key_tests')").formats(@access_keys_format) do + Fog::AWS[:iam].list_access_keys('UserName' => 'fog_access_key_tests').body + end + + tests("#update_access_key('#{@access_key_id}', 'Inactive', 'UserName' => 'fog_access_key_tests')").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].update_access_key(@access_key_id, 'Inactive', 'UserName' => 'fog_access_key_tests').body + end + + tests("#delete_access_key('#{@access_key_id}', 'UserName' => 'fog_access_key_tests)").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].delete_access_key(@access_key_id, 'UserName' => 'fog_access_key_tests').body + end + + end + + tests('failure') do + test('failing conditions') + end + + Fog::AWS[:iam].delete_user('fog_access_key_tests') + +end diff --git a/tests/requests/iam/account_policy_tests.rb b/tests/requests/iam/account_policy_tests.rb new file mode 100644 index 000000000..3c7ece379 --- /dev/null +++ b/tests/requests/iam/account_policy_tests.rb @@ -0,0 +1,20 @@ +Shindo.tests('Aws::IAM | account policy requests', ['aws']) do + + tests('success') do + tests("#update_account_password_policy(minimum_password_length, max_password_age, password_reuse_prevention,require_symbols,require_numbers,require_uppercase_characters, require_lowercase_characters,allow_users_to_change_password, hard_expiry, expire_passwords)").formats(Aws::IAM::Formats::BASIC) do + minimum_password_length, password_reuse_prevention, max_password_age = 5 + require_symbols, require_numbers, require_uppercase_characters, require_lowercase_characters, allow_users_to_change_password, hard_expiry, expire_passwords = false + + Fog::AWS[:iam].update_account_password_policy(minimum_password_length, max_password_age, password_reuse_prevention,require_symbols,require_numbers,require_uppercase_characters, require_lowercase_characters,allow_users_to_change_password, hard_expiry, expire_passwords).body + end + + tests("#get_account_password_policy()") do + Fog::AWS[:iam].get_account_password_policy().body['AccountPasswordPolicy'] + end + + tests("#delete_account_password_policy()").formats(Aws::IAM::Formats::BASIC) do + + Fog::AWS[:iam].delete_account_password_policy().body + end + end +end diff --git a/tests/requests/iam/account_tests.rb b/tests/requests/iam/account_tests.rb new file mode 100644 index 000000000..7e55656bc --- /dev/null +++ b/tests/requests/iam/account_tests.rb @@ -0,0 +1,34 @@ +Shindo.tests('Aws::IAM | account requests', ['aws']) do + tests('success') do + @get_account_summary_format = { + 'Summary' => { + 'AccessKeysPerUserQuota' => Integer, + 'AccountMFAEnabled' => Integer, + 'AssumeRolePolicySizeQuota' => Fog::Nullable::Integer, + 'GroupPolicySizeQuota' => Integer, + 'Groups' => Integer, + 'GroupsPerUserQuota' => Integer, + 'GroupsQuota' => Integer, + 'InstanceProfiles' => Fog::Nullable::Integer, + 'InstanceProfilesQuota' => Fog::Nullable::Integer, + 'MFADevices' => Integer, + 'MFADevicesInUse' => Integer, + 'Providers' => Fog::Nullable::Integer, + 'RolePolicySizeQuota' => Fog::Nullable::Integer, + 'Roles' => Fog::Nullable::Integer, + 'RolesQuota' => Fog::Nullable::Integer, + 'ServerCertificates' => Integer, + 'ServerCertificatesQuota' => Integer, + 'SigningCertificatesPerUserQuota' => Integer, + 'UserPolicySizeQuota' => Integer, + 'Users' => Integer, + 'UsersQuota' => Integer, + }, + 'RequestId' => String, + } + + tests('#get_account_summary').formats(@get_account_summary_format) do + Fog::AWS[:iam].get_account_summary.body + end + end +end diff --git a/tests/requests/iam/group_policy_tests.rb b/tests/requests/iam/group_policy_tests.rb new file mode 100644 index 000000000..ed808c710 --- /dev/null +++ b/tests/requests/iam/group_policy_tests.rb @@ -0,0 +1,48 @@ +Shindo.tests('Aws::IAM | group policy requests', ['aws']) do + + Fog::AWS[:iam].create_group('fog_group_policy_tests') + + tests('success') do + + @policy = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]} + + tests("#put_group_policy('fog_group_policy_tests', 'fog_policy', #{@policy.inspect})").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].put_group_policy('fog_group_policy_tests', 'fog_policy', @policy).body + end + + @group_policies_format = { + 'IsTruncated' => Fog::Boolean, + 'PolicyNames' => [String], + 'RequestId' => String + } + + tests("list_group_policies('fog_group_policy_tests')").formats(@group_policies_format) do + pending if Fog.mocking? + Fog::AWS[:iam].list_group_policies('fog_group_policy_tests').body + end + + @group_policy_format = { + 'GroupName' => String, + 'PolicyName' => String, + 'PolicyDocument' => Hash, + } + + tests("#get_group_policy('fog_group_policy_tests', 'fog_policy'").formats(@group_policy_format) do + Fog::AWS[:iam].get_group_policy('fog_policy', 'fog_group_policy_tests').body['Policy'] + end + + tests("#delete_group_policy('fog_group_policy_tests', 'fog_policy')").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].delete_group_policy('fog_group_policy_tests', 'fog_policy').body + end + end + + tests('failure') do + test('failing conditions') + end + + unless Fog.mocking? + Fog::AWS[:iam].delete_group('fog_group_policy_tests') + end + +end diff --git a/tests/requests/iam/group_tests.rb b/tests/requests/iam/group_tests.rb new file mode 100644 index 000000000..08dd22845 --- /dev/null +++ b/tests/requests/iam/group_tests.rb @@ -0,0 +1,44 @@ +Shindo.tests('Aws::IAM | group requests', ['aws']) do + + tests('success') do + + @group_format = { + 'Group' => { + 'Arn' => String, + 'GroupId' => String, + 'GroupName' => String, + 'Path' => String + }, + 'RequestId' => String + } + + tests("#create_group('fog_group')").formats(@group_format) do + Fog::AWS[:iam].create_group('fog_group').body + end + + @groups_format = { + 'Groups' => [{ + 'Arn' => String, + 'GroupId' => String, + 'GroupName' => String, + 'Path' => String + }], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + } + + tests("#list_groups").formats(@groups_format) do + Fog::AWS[:iam].list_groups.body + end + + tests("#delete_group('fog_group')").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].delete_group('fog_group').body + end + + end + + tests('failure') do + test('failing conditions') + end + +end diff --git a/tests/requests/iam/helper.rb b/tests/requests/iam/helper.rb new file mode 100644 index 000000000..9a61798eb --- /dev/null +++ b/tests/requests/iam/helper.rb @@ -0,0 +1,102 @@ +class Aws + module IAM + # A self-signed test keypair. Generated using the command: + # openssl req -new -newkey rsa:1024 -days 3650 -nodes -x509 -keyout server-private.key -out server-public.crt + # NB: Amazon returns an error on extraneous linebreaks + SERVER_CERT = %{-----BEGIN CERTIFICATE----- +MIIDQzCCAqygAwIBAgIJAJaZ8wH+19AtMA0GCSqGSIb3DQEBBQUAMHUxCzAJBgNV +BAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazERMA8GA1UEBxMITmV3IFlvcmsxHzAd +BgNVBAoTFkZvZyBUZXN0IFNuYWtlb2lsIENlcnQxHzAdBgNVBAsTFkZvZyBUZXN0 +IFNuYWtlb2lsIENlcnQwHhcNMTEwNTA3MTc0MDU5WhcNMjEwNTA0MTc0MDU5WjB1 +MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZ +b3JrMR8wHQYDVQQKExZGb2cgVGVzdCBTbmFrZW9pbCBDZXJ0MR8wHQYDVQQLExZG +b2cgVGVzdCBTbmFrZW9pbCBDZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQC0CR76sovjdmpWRmEaf8XaG+nGe7czhpdLKkau2b16VtSjkPctxPL5U4vaMxQU +boLPr+9oL+9fSYN31VzDD4hyaeGoeI5fhnGeqk71kq5uHONBOQUMbZbBQ8PVd9Sd +k+y9JJ6E5fC+GhLL5I+y2DK7syBzyymq1Wi6rPp1XXF7AQIDAQABo4HaMIHXMB0G +A1UdDgQWBBRfqBkpU/jEV324748fq6GJM80iVTCBpwYDVR0jBIGfMIGcgBRfqBkp +U/jEV324748fq6GJM80iVaF5pHcwdTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5l +dyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEfMB0GA1UEChMWRm9nIFRlc3QgU25h +a2VvaWwgQ2VydDEfMB0GA1UECxMWRm9nIFRlc3QgU25ha2VvaWwgQ2VydIIJAJaZ +8wH+19AtMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAUV6NDdLHKNhl +ACtzLycIhlMTmDr0xBeIBx3lpgw2K0+4oefMS8Z17eeZPeNodxnz56juJm81BZwt +DF3qnnPyArLFx0HLB7wQdm9xYVIqQuLO+V6GRuOd+uSX//aDLDZhwbERf35hoyto +Jfk4gX/qwuRFNy0vjQeTzdvhB1igG/w= +-----END CERTIFICATE----- +} + # The public key for SERVER_CERT. Generated using the command: + # openssl x509 -inform pem -in server-public.crt -pubkey -noout > server.pubkey + SERVER_CERT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0CR76sovjdmpWRmEaf8XaG+nGe7czhpdLKkau2b16VtSjkPctxPL5U4vaMxQUboLPr+9oL+9fSYN31VzDD4hyaeGoeI5fhnGeqk71kq5uHONBOQUMbZbBQ8PVd9Sdk+y9JJ6E5fC+GhLL5I+y2DK7syBzyymq1Wi6rPp1XXF7AQIDAQAB" + + SERVER_CERT_PRIVATE_KEY = %{-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC0CR76sovjdmpWRmEaf8XaG+nGe7czhpdLKkau2b16VtSjkPct +xPL5U4vaMxQUboLPr+9oL+9fSYN31VzDD4hyaeGoeI5fhnGeqk71kq5uHONBOQUM +bZbBQ8PVd9Sdk+y9JJ6E5fC+GhLL5I+y2DK7syBzyymq1Wi6rPp1XXF7AQIDAQAB +AoGANjjRBbwkeXs+h4Fm2W5GDmx9ufOkt3X/tvmilCKr+F6SaDjO2RAKBaFt62ea +0pR9/UMFnaFiPJaNa9fsuirBcwId+RizruEp+7FGziM9mC5kcE7WKZrXgGGnLtqg +4x5twVLArgp0ji7TA18q/74uTrI4az8H5iTY4n29ORlLmmkCQQDsGMuLEgGHgN5Y +1c9ax1DT/rUXKxnqsIrijRkgbiTncHAArFJ88c3yykWqGvYnSFwMS8DSWiPyPaAI +nNNlb/fPAkEAwzZ4CfvJ+OlE++rTPH9jemC89dnxC7EFGuWJmwdadnev8EYguvve +cdGdGttD7QsZKpcz5mDngOUghbVm8vBELwJAMHfOoVgq9DRicP5DuTEdyMeLSZxR +j7p6aJPqypuR++k7NQgrTvcc/nDD6G3shpf2PZf3l7dllb9M8TewtixMRQJBAIdX +c0AQtoYBTJePxiYyd8i32ypkkK83ar+sFoxKO9jYwD1IkZax2xZ0aoTdMindQPR7 +Yjs+QiLmOHcbPqX+GHcCQERsSn0RjzKmKirDntseMB59BB/cEN32+gMDVsZuCfb+ +fOy2ZavFl13afnhbh2/AjKeDhnb19x/uXjF7JCUtwpA= +-----END RSA PRIVATE KEY----- +} + + # openssl pkcs8 -nocrypt -topk8 -in SERVER_CERT_PRIVATE_KEY.key -outform pem + SERVER_CERT_PRIVATE_KEY_PKCS8 = %{-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALQJHvqyi+N2alZG +YRp/xdob6cZ7tzOGl0sqRq7ZvXpW1KOQ9y3E8vlTi9ozFBRugs+v72gv719Jg3fV +XMMPiHJp4ah4jl+GcZ6qTvWSrm4c40E5BQxtlsFDw9V31J2T7L0knoTl8L4aEsvk +j7LYMruzIHPLKarVaLqs+nVdcXsBAgMBAAECgYA2ONEFvCR5ez6HgWbZbkYObH25 +86S3df+2+aKUIqv4XpJoOM7ZEAoFoW3rZ5rSlH39QwWdoWI8lo1r1+y6KsFzAh35 +GLOu4Sn7sUbOIz2YLmRwTtYpmteAYacu2qDjHm3BUsCuCnSOLtMDXyr/vi5Osjhr +PwfmJNjifb05GUuaaQJBAOwYy4sSAYeA3ljVz1rHUNP+tRcrGeqwiuKNGSBuJOdw +cACsUnzxzfLKRaoa9idIXAxLwNJaI/I9oAic02Vv988CQQDDNngJ+8n46UT76tM8 +f2N6YLz12fELsQUa5YmbB1p2d6/wRiC6+95x0Z0a20PtCxkqlzPmYOeA5SCFtWby +8EQvAkAwd86hWCr0NGJw/kO5MR3Ix4tJnFGPunpok+rKm5H76Ts1CCtO9xz+cMPo +beyGl/Y9l/eXt2WVv0zxN7C2LExFAkEAh1dzQBC2hgFMl4/GJjJ3yLfbKmSQrzdq +v6wWjEo72NjAPUiRlrHbFnRqhN0yKd1A9HtiOz5CIuY4dxs+pf4YdwJARGxKfRGP +MqYqKsOe2x4wHn0EH9wQ3fb6AwNWxm4J9v587LZlq8WXXdp+eFuHb8CMp4OGdvX3 +H+5eMXskJS3CkA== +-----END PRIVATE KEY----- +} + + SERVER_CERT_PRIVATE_KEY_MISMATCHED = %{-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAyITMqYJMzkPMcaC+x0W2hnZVW99RXzLR8RYyD3xo2AotdJKx +1DXR4ryegAjsnAhJVwVtxqzPcBMq/XS0hNtWFfKzf+vMZl7uAqotGjURUV8SRQPA +8tT07MemD929xRSV2vTnVATiPn87vcu5igsZ01+Ewd6rGythmvcZD13vtZ4rx0c8 +kQJV3ok/CkFaIgDR6Or1NZBCtcIVK9nvqAmYMp6S5mWUMIsl/1qYPerpefrSJjlk +J2+jyLp0LHarbzjkzzAdOkBRX1hPkk6cisBeQIpx35shLzfCe8U25XNqquP+ftcu +JZ0Wjw+C4pTIzfgdGXmGGtBFY13BwiJvd4/i2wIDAQABAoIBABk8XWWX+IKdFcXX +LSt3IpmZmvSNDniktLday8IXLjrCTSY2sBq9C0U159zFQsIAaPqCvGYcqZ65StfL +MEzoLdVlTiHzUy4vFFVRhYue0icjh/EXn9jv5ENIfSXSCmgbRyDfYZ25X5/t817X +nOo6q21mwBaGJ5KrywTtxEGi2OBKZrIbBrpJLhCXJc5xfuKT6DRa9X/OBSBiGKJP +V9wHcZJkPG1HnC8izvQ37kNN/NyYE+8AGdYXQVNbTHq/emNLbEbdcR3tpGZamM9Q +TwG5WsDPAnXnRsEEYvlVTOBI6DqdvkyBxM35iqd5aAc6i/Iu04Unfhhc5pAXmmIB +a22GHcECgYEA7OheVHDDP8quO2qZjqaTlMbMnXnrFXJ41llFMoivTW9EmlTl9dOC +fnkHEBcFCTPV0m6S2AQjt9QOgPqCFAq1r3J/xvEGBtl/UKnPRmjqXFgl0ENtGn5t +w9wj/CsOPD05KkXXtXP+MyLPRD6gAxiQCTnXjvsLuVfP+E9BO2EQXScCgYEA2K2x +QtcAAalrk3c0KzNVESzyFlf3ddEXThShVblSa7r6Ka9q9sxN/Xe2B+1oemPJm26G +PfqKgxdKX0R0jl4f5pRBWKoarzWtUge/su8rx/xzbY/1hFKVuimtc6oTeU5xsOTS +PVuCz4bxDTVhrbmKqbmMgqy17jfPA4BrF1FMRS0CgYBdMA4i4vQ6fIxKfOUIMsfs +hsJn01RAbHXRwu2wMgnayMDQgEKwjtFO1GaN0rA9bXFXQ/1pET/HiJdn7qIKJihP +aheO9rHrMdSdsx4AUTaWummtYUhiWobsuwRApeMEmQSKd0yhaI3+KVwkOQoSDbBi +oKkE6gUzk7IPt4UuSUD5kwKBgQCjo/IGr8dieegz08gDhF4PfalLdJ4ATaxTHMOH +sVFs6SY7Sy72Ou//qGRCcmsAW9KL35nkvw3S2Ukiz9lTGATxqC/93WIPxvMhy5Zc +dcLT43XtXdanW5OWqBlGDEFu0O6OERIyoqUVRC1Ss2kUwdbWPbq/id5Qjbd7RoYa +cxyt9QKBgF4bFLw1Iw2RBngQxIzoDbElEqme20FUyGGzyFQtxVwmwNr4OY5UzJzX +7G6diyzGrvRX81Yw616ppKJUJVr/zRc13K+eRXXKtNpGkf35B+1NDDjjWZpIHqgx +Xb9WSr07saxZQbxBPQyTlb0Q9Tu2djAq2/o/nYD1/50/fXUTuWMB +-----END RSA PRIVATE KEY----- +} + + module Formats + BASIC = { + 'RequestId' => String + } + end + end +end diff --git a/tests/requests/iam/login_profile_tests.rb b/tests/requests/iam/login_profile_tests.rb new file mode 100644 index 000000000..c6b0f6185 --- /dev/null +++ b/tests/requests/iam/login_profile_tests.rb @@ -0,0 +1,62 @@ +Shindo.tests('Aws::IAM | user requests', ['aws']) do + + unless Fog.mocking? + Fog::AWS[:iam].create_user('fog_user') + end + + tests('success') do + @login_profile_format = { + 'LoginProfile' => { + 'UserName' => String, + 'CreateDate' => Time + + }, + 'RequestId' => String + } + + tests("#create_login_profile('fog_user')").formats(@login_profile_format) do + pending if Fog.mocking? + Fog::AWS[:iam].create_login_profile('fog_user', 'somepassword').body + end + + tests("#get_login_profile('fog_user')").formats(@login_profile_format) do + pending if Fog.mocking? + result = Fog::AWS[:iam].get_login_profile('fog_user').body + returns('fog_user') {result['LoginProfile']['UserName']} + result + end + + tests("#update_login_profile('fog_user')").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + begin + Fog::AWS[:iam].update_login_profile('fog_user', 'otherpassword').body + rescue Excon::Errors::Conflict #profile cannot be updated or deleted until it has finished creating; api provides no way of telling whether creation process complete + sleep 5 + retry + end + end + + tests("#delete_login_profile('fog_user')").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].delete_login_profile('fog_user').body + end + + tests("#get_login_profile('fog_user')") do + pending if Fog.mocking? + raises(Excon::Errors::NotFound) {Fog::AWS[:iam].get_login_profile('fog_user')} + end + + end + + tests('failure') do + tests('get login profile for non existing user') do + pending if Fog.mocking? + raises(Fog::AWS::IAM::NotFound) { Fog::AWS[:iam].get_login_profile('idontexist')} + raises(Fog::AWS::IAM::NotFound) { Fog::AWS[:iam].delete_login_profile('fog_user')} + end + end + + unless Fog.mocking? + Fog::AWS[:iam].delete_user('fog_user') + end +end diff --git a/tests/requests/iam/mfa_tests.rb b/tests/requests/iam/mfa_tests.rb new file mode 100644 index 000000000..65a86d06f --- /dev/null +++ b/tests/requests/iam/mfa_tests.rb @@ -0,0 +1,23 @@ +Shindo.tests('Aws::IAM | mfa requests', ['aws']) do + + tests('success') do + @mfa_devices_format = { + 'MFADevices' => [{ + 'EnableDate' => Time, + 'SerialNumber' => String, + 'UserName' => String + }], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + } + + tests('#list_mfa_devices').formats(@mfa_devices_format) do + Fog::AWS[:iam].list_mfa_devices.body + end + end + + tests('failure') do + test('failing conditions') + end + +end diff --git a/tests/requests/iam/role_tests.rb b/tests/requests/iam/role_tests.rb new file mode 100644 index 000000000..0f55937e3 --- /dev/null +++ b/tests/requests/iam/role_tests.rb @@ -0,0 +1,167 @@ +Shindo.tests('Aws::IAM | role requests', ['aws']) do + tests('success') do + + @role = { + 'Arn' => String, + 'AssumeRolePolicyDocument' => String, + 'CreateDate' => Time, + 'Path' => String, + 'RoleId' => String, + 'RoleName' => String + } + @role_format = { + 'Role' => @role, + 'RequestId' => String + } + tests("#create_role('fogrole')").formats(@role_format) do + pending if Fog.mocking? + Fog::AWS[:iam].create_role('fogrole', Fog::AWS::IAM::EC2_ASSUME_ROLE_POLICY).body + end + + tests("#get_role('fogrole')").formats(@role_format) do + pending if Fog.mocking? + Fog::AWS[:iam].get_role('fogrole').body + end + + @list_roles_format = { + 'Roles' => [{ + 'Arn' => String, + 'AssumeRolePolicyDocument' => String, + 'CreateDate' => Time, + 'Path' => String, + 'RoleId' => String, + 'RoleName' => String + }], + 'RequestId' => String, + 'IsTruncated' => Fog::Boolean, + } + + tests("#list_roles").formats(@list_roles_format) do + pending if Fog.mocking? + body = Fog::AWS[:iam].list_roles.body + returns(true){!! body['Roles'].find {|role| role['RoleName'] == 'fogrole'}} + body + end + + @profile_format = { + 'InstanceProfile' => { + 'Arn' => String, + 'CreateDate' => Time, + 'Path' => String, + 'InstanceProfileId' => String, + 'InstanceProfileName' => String, + 'Roles' => [@role] + }, + 'RequestId' => String + + } + tests("#create_instance_profile('fogprofile')").formats(@profile_format) do + pending if Fog.mocking? + Fog::AWS[:iam].create_instance_profile('fogprofile').body + end + + tests("#get_instance_profile('fogprofile')").formats(@profile_format) do + pending if Fog.mocking? + Fog::AWS[:iam].get_instance_profile('fogprofile').body + end + + tests("#add_role_to_instance_profile('fogprofile','fogrole')").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].add_role_to_instance_profile('fogrole', 'fogprofile').body + end + + @profiles_format = { + 'InstanceProfiles' => [{ + 'Arn' => String, + 'CreateDate' => Time, + 'Path' => String, + 'InstanceProfileId' => String, + 'InstanceProfileName' => String, + 'Roles' => [@role] + }], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + + } + tests("list_instance_profiles_for_role('fogrole')").formats(@profiles_format) do + pending if Fog.mocking? + body = Fog::AWS[:iam].list_instance_profiles_for_role('fogrole').body + returns(['fogprofile']) { body['InstanceProfiles'].map {|hash| hash['InstanceProfileName']}} + body + end + + tests("list_instance_profiles").formats(@profiles_format) do + pending if Fog.mocking? + Fog::AWS[:iam].list_instance_profiles.body + end + + sample_policy = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]} + + tests("put_role_policy").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].put_role_policy('fogrole', 'fogpolicy', sample_policy).body + end + + @get_role_policy_format = { + 'Policy' => { + 'RoleName' => String, + 'PolicyName' => String, + 'PolicyDocument' => Hash, + }, + 'RequestId' => String + } + + tests("get_role_policy").formats(@get_role_policy_format) do + pending if Fog.mocking? + body = Fog::AWS[:iam].get_role_policy('fogrole','fogpolicy').body + returns('fogpolicy') {body['Policy']['PolicyName']} + returns(sample_policy){body['Policy']['PolicyDocument']} + body + end + + @list_role_policies_format = { + 'PolicyNames' => [String], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + } + + tests("list_role_policies").formats(@list_role_policies_format) do + pending if Fog.mocking? + body = Fog::AWS[:iam].list_role_policies('fogrole').body + + returns(['fogpolicy']) {body['PolicyNames']} + body + end + + tests("delete_role_policy").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].delete_role_policy('fogrole', 'fogpolicy').body + end + + returns([]) do + pending if Fog.mocking? + Fog::AWS[:iam].list_role_policies('fogrole').body['PolicyNames'] + end + + tests("remove_role_from_instance_profile").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].remove_role_from_instance_profile('fogrole', 'fogprofile').body + end + + returns([]) do + pending if Fog.mocking? + Fog::AWS[:iam].list_instance_profiles_for_role('fogrole').body['InstanceProfiles'] + end + + tests("#delete_instance_profile('fogprofile'").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].delete_instance_profile('fogprofile').body + end + + tests("#delete_role('fogrole'").formats(Aws::IAM::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:iam].delete_role('fogrole').body + end + end + +end diff --git a/tests/requests/iam/server_certificate_tests.rb b/tests/requests/iam/server_certificate_tests.rb new file mode 100644 index 000000000..8a880607f --- /dev/null +++ b/tests/requests/iam/server_certificate_tests.rb @@ -0,0 +1,130 @@ +Shindo.tests('Aws::IAM | server certificate requests', ['aws']) do + @key_name = 'fog-test' + @key_name_chained = 'fog-test-chained' + + @certificate_format = { + 'Arn' => String, + 'Path' => String, + 'ServerCertificateId' => String, + 'ServerCertificateName' => String, + 'UploadDate' => Time + } + @upload_format = { + 'Certificate' => @certificate_format, + 'RequestId' => String + } + @update_format = { + 'RequestId' => String + } + @get_server_certificate_format = { + 'Certificate' => @certificate_format, + 'RequestId' => String + } + @list_format = { + 'Certificates' => [@certificate_format] + } + + tests('#upload_server_certificate') do + public_key = Aws::IAM::SERVER_CERT + private_key = Aws::IAM::SERVER_CERT_PRIVATE_KEY + private_key_pkcs8 = Aws::IAM::SERVER_CERT_PRIVATE_KEY_PKCS8 + private_key_mismatch = Aws::IAM::SERVER_CERT_PRIVATE_KEY_MISMATCHED + + tests('empty public key').raises(Fog::AWS::IAM::ValidationError) do + Fog::AWS::IAM.new.upload_server_certificate('', private_key, @key_name) + end + + tests('empty private key').raises(Fog::AWS::IAM::ValidationError) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, '', @key_name) + end + + tests('invalid public key').raises(Fog::AWS::IAM::MalformedCertificate) do + Fog::AWS::IAM.new.upload_server_certificate('abcde', private_key, @key_name) + end + + tests('invalid private key').raises(Fog::AWS::IAM::MalformedCertificate) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, 'abcde', @key_name) + end + + tests('non-RSA private key').raises(Fog::AWS::IAM::MalformedCertificate) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key_pkcs8, @key_name) + end + + tests('mismatched private key').raises(Fog::AWS::IAM::KeyPairMismatch) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key_mismatch, @key_name) + end + + tests('format').formats(@upload_format) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, @key_name).body + end + + tests('format with chain').formats(@upload_format) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, @key_name_chained, { 'CertificateChain' => public_key }).body + end + + tests('duplicate name').raises(Fog::AWS::IAM::EntityAlreadyExists) do + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, @key_name) + end + end + + tests('#update_server_certificate') do + public_key = Aws::IAM::SERVER_CERT + private_key = Aws::IAM::SERVER_CERT_PRIVATE_KEY + key_name = "update-key" + + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, key_name) + + tests('duplicate name').raises(Fog::AWS::IAM::EntityAlreadyExists) do + other_key_name = "other-key-name" + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, other_key_name) + + Fog::AWS::IAM.new.update_server_certificate(key_name, {'NewServerCertificateName' => other_key_name}) + end + + tests('unknown name').raises(Fog::AWS::IAM::NotFound) do + Fog::AWS::IAM.new.update_server_certificate("unknown-key-name", {'NewServerCertificateName' => "other-keyname"}) + end + + tests('format').formats(@update_format) do + Fog::AWS::IAM.new.update_server_certificate(key_name).body + end + + tests('updates name') do + other_key_name = "successful-update-key-name" + Fog::AWS::IAM.new.update_server_certificate(key_name, {'NewServerCertificateName' => other_key_name}) + returns(true) { Fog::AWS::IAM.new.get_server_certificate(other_key_name).body['Certificate']['ServerCertificateName'] == other_key_name } + end + end + + tests('#get_server_certificate').formats(@get_server_certificate_format) do + tests('raises NotFound').raises(Fog::AWS::IAM::NotFound) do + Fog::AWS::IAM.new.get_server_certificate("#{@key_name}fake") + end + Fog::AWS::IAM.new.get_server_certificate(@key_name).body + end + + tests('#list_server_certificates').formats(@list_format) do + result = Fog::AWS::IAM.new.list_server_certificates.body + tests('includes key name') do + returns(true) { result['Certificates'].any?{|c| c['ServerCertificateName'] == @key_name} } + end + result + end + + tests("#list_server_certificates('path-prefix' => '/'").formats(@list_format) do + result = Fog::AWS::IAM.new.list_server_certificates('PathPrefix' => '/').body + tests('includes key name') do + returns(true) { result['Certificates'].any?{|c| c['ServerCertificateName'] == @key_name} } + end + result + end + + tests('#delete_server_certificate').formats(Aws::IAM::Formats::BASIC) do + tests('raises NotFound').raises(Fog::AWS::IAM::NotFound) do + Fog::AWS::IAM.new.delete_server_certificate("#{@key_name}fake") + end + Fog::AWS::IAM.new.delete_server_certificate(@key_name).body + end + + Fog::AWS::IAM.new.delete_server_certificate(@key_name_chained) +end diff --git a/tests/requests/iam/user_policy_tests.rb b/tests/requests/iam/user_policy_tests.rb new file mode 100644 index 000000000..901465e13 --- /dev/null +++ b/tests/requests/iam/user_policy_tests.rb @@ -0,0 +1,45 @@ +Shindo.tests('Aws::IAM | user policy requests', ['aws']) do + + Fog::AWS[:iam].create_user('fog_user_policy_tests') + + tests('success') do + + @policy = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]} + + tests("#put_user_policy('fog_user_policy_tests', 'fog_policy', #{@policy.inspect})").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].put_user_policy('fog_user_policy_tests', 'fog_policy', @policy).body + end + + @user_policies_format = { + 'IsTruncated' => Fog::Boolean, + 'PolicyNames' => [String], + 'RequestId' => String + } + + tests("#list_user_policies('fog_user_policy_tests')").formats(@user_policies_format) do + Fog::AWS[:iam].list_user_policies('fog_user_policy_tests').body + end + + @user_policy_format = { + 'UserName' => String, + 'PolicyName' => String, + 'PolicyDocument' => Hash, + } + + tests("#get_user_policy('fog_user_policy_tests', 'fog_policy'").formats(@user_policy_format) do + Fog::AWS[:iam].get_user_policy('fog_policy', 'fog_user_policy_tests').body['Policy'] + end + + tests("#delete_user_policy('fog_user_policy_tests', 'fog_policy')").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].delete_user_policy('fog_user_policy_tests', 'fog_policy').body + end + + end + + tests('failure') do + test('failing conditions') + end + + Fog::AWS[:iam].delete_user('fog_user_policy_tests') + +end diff --git a/tests/requests/iam/user_tests.rb b/tests/requests/iam/user_tests.rb new file mode 100644 index 000000000..b894264de --- /dev/null +++ b/tests/requests/iam/user_tests.rb @@ -0,0 +1,77 @@ +Shindo.tests('Aws::IAM | user requests', ['aws']) do + + Fog::AWS[:iam].create_group('fog_user_tests') + + tests('success') do + + @user_format = { + 'User' => { + 'Arn' => String, + 'Path' => String, + 'UserId' => String, + 'UserName' => String, + 'CreateDate' => Time + }, + 'RequestId' => String + } + + tests("#create_user('fog_user')").formats(@user_format) do + Fog::AWS[:iam].create_user('fog_user').body + end + + @users_format = { + 'Users' => [{ + 'Arn' => String, + 'Path' => String, + 'UserId' => String, + 'UserName' => String, + 'CreateDate' => Time + }], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + } + + tests("#list_users").formats(@users_format) do + Fog::AWS[:iam].list_users.body + end + + tests("#get_user").formats(@user_format) do + Fog::AWS[:iam].get_user('fog_user').body + end + + tests("#add_user_to_group('fog_user_tests', 'fog_user')").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].add_user_to_group('fog_user_tests', 'fog_user').body + end + + @groups_format = { + 'GroupsForUser' => [{ + 'Arn' => String, + 'GroupId' => String, + 'GroupName' => String, + 'Path' => String + }], + 'IsTruncated' => Fog::Boolean, + 'RequestId' => String + } + + tests("#list_groups_for_user('fog_user')").formats(@groups_format) do + Fog::AWS[:iam].list_groups_for_user('fog_user').body + end + + tests("#remove_user_from_group('fog_user_tests', 'fog_user')").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].remove_user_from_group('fog_user_tests', 'fog_user').body + end + + tests("#delete_user('fog_user')").formats(Aws::IAM::Formats::BASIC) do + Fog::AWS[:iam].delete_user('fog_user').body + end + + end + + tests('failure') do + test('failing conditions') + end + + Fog::AWS[:iam].delete_group('fog_user_tests') + +end diff --git a/tests/requests/rds/describe_events.rb b/tests/requests/rds/describe_events.rb new file mode 100644 index 000000000..02ce168d5 --- /dev/null +++ b/tests/requests/rds/describe_events.rb @@ -0,0 +1,16 @@ +Shindo.tests('Aws::RDS | describe DB events requests',['aws', 'rds']) do + + tests('success') do + pending if Fog.mocking? + + tests( + '#describe_events' + ).formats(Aws::RDS::Formats::EVENT_LIST) do + Aws[:rds].describe_events().body['Events'] + end + end + + tests('failure') do + #TODO: What constitutes a failure here? + end +end diff --git a/tests/requests/rds/event_subscription_tests.rb b/tests/requests/rds/event_subscription_tests.rb new file mode 100644 index 000000000..3de961069 --- /dev/null +++ b/tests/requests/rds/event_subscription_tests.rb @@ -0,0 +1,30 @@ +Shindo.tests('Aws::RDS | event subscription requests', ['aws', 'rds']) do + pending unless Fog.mocking? + + @name = 'fog' + @arn = 'arn:aws:sns:us-east-1:12345678910:fog' + + tests('success') do + tests('#create_event_subscription').formats(Aws::RDS::Formats::CREATE_EVENT_SUBSCRIPTION) do + body = Fog::AWS[:rds].create_event_subscription('SubscriptionName' => @name, 'SnsTopicArn' => @arn).body + + returns(@name) { body['CreateEventSubscriptionResult']['EventSubscription']['CustSubscriptionId'] } + returns('creating') { body['CreateEventSubscriptionResult']['EventSubscription']['Status'] } + body + end + + tests("#describe_event_subscriptions").formats(Aws::RDS::Formats::DESCRIBE_EVENT_SUBSCRIPTIONS) do + returns('active') { Fog::AWS[:rds].describe_event_subscriptions.body['DescribeEventSubscriptionsResult']['EventSubscriptionsList'].first['Status'] } + Fog::AWS[:rds].describe_event_subscriptions.body + end + + tests("#delete_event_subscription").formats(Aws::RDS::Formats::BASIC) do + body = Fog::AWS[:rds].delete_event_subscription(@name).body + + returns('deleting') { Fog::AWS[:rds].describe_event_subscriptions('SubscriptionName' => @name).body['DescribeEventSubscriptionsResult']['EventSubscriptionsList'].first['Status'] } + raises(Fog::AWS::RDS::NotFound) { Fog::AWS[:rds].describe_event_subscriptions('SubscriptionName' => @name) } + + body + end + end +end diff --git a/tests/requests/rds/helper.rb b/tests/requests/rds/helper.rb new file mode 100644 index 000000000..525ca99df --- /dev/null +++ b/tests/requests/rds/helper.rb @@ -0,0 +1,296 @@ +class Aws + module RDS + module Formats + BASIC = { + 'ResponseMetadata' => { 'RequestId' => String } + } + + DB_AVAILABILITY_ZONE_OPTION = { + 'Name' => String, + 'ProvisionedIopsCapable' => Fog::Boolean + } + + DB_PARAMETER_GROUP = { + 'DBParameterGroupFamily' => String, + 'DBParameterGroupName' => String, + 'Description' => String + } + CREATE_DB_PARAMETER_GROUP = { + 'ResponseMetadata' => { 'RequestId' => String }, + 'CreateDBParameterGroupResult' => { + 'DBParameterGroup' => DB_PARAMETER_GROUP + } + } + + DB_SECURITY_GROUP = { + 'DBSecurityGroupDescription' => String, + 'DBSecurityGroupName' => String, + 'EC2SecurityGroups' => [Fog::Nullable::Hash], + 'IPRanges' => [Fog::Nullable::Hash], + 'OwnerId' => Fog::Nullable::String + } + + CREATE_DB_SECURITY_GROUP = BASIC.merge({ + 'CreateDBSecurityGroupResult' => { + 'DBSecurityGroup' => DB_SECURITY_GROUP + } + }) + + AUTHORIZE_DB_SECURITY_GROUP = BASIC.merge({ + 'AuthorizeDBSecurityGroupIngressResult' => { + 'DBSecurityGroup' => DB_SECURITY_GROUP + } + }) + + REVOKE_DB_SECURITY_GROUP = BASIC.merge({ + 'RevokeDBSecurityGroupIngressResult' => { + 'DBSecurityGroup' => DB_SECURITY_GROUP + } + }) + + DESCRIBE_DB_SECURITY_GROUP = BASIC.merge({ + 'DescribeDBSecurityGroupsResult' => { + 'DBSecurityGroups' => [DB_SECURITY_GROUP] + } + }) + + DB_SUBNET_GROUP = { + 'DBSubnetGroupName' => String, + 'DBSubnetGroupDescription' => String, + 'SubnetGroupStatus' => String, + 'VpcId' => String, + 'Subnets' => [String] + } + + CREATE_DB_SUBNET_GROUP = BASIC.merge({ + 'CreateDBSubnetGroupResult' => { + 'DBSubnetGroup' => DB_SUBNET_GROUP + } + }) + + DESCRIBE_DB_SUBNET_GROUPS = BASIC.merge({ + 'DescribeDBSubnetGroupsResult' => { + 'DBSubnetGroups' => [DB_SUBNET_GROUP] + } + }) + + DESCRIBE_DB_PARAMETER_GROUP = { + 'ResponseMetadata' => { 'RequestId' => String }, + 'DescribeDBParameterGroupsResult' => { + 'DBParameterGroups' => [DB_PARAMETER_GROUP] + } + } + + ORDERABLE_DB_INSTANCE_OPTION = { + 'MultiAZCapable' => Fog::Boolean, + 'Engine' => String, + 'LicenseModel' => String, + 'ReadReplicaCapable' => Fog::Boolean, + 'EngineVersion' => String, + 'AvailabilityZones' => [DB_AVAILABILITY_ZONE_OPTION], + 'DBInstanceClass' => String, + 'Vpc' => Fog::Boolean + } + + DESCRIBE_ORDERABLE_DB_INSTANCE_OPTION = BASIC.merge({ + 'DescribeOrderableDBInstanceOptionsResult' => { + 'OrderableDBInstanceOptions' => [ORDERABLE_DB_INSTANCE_OPTION] + } + }) + + MODIFY_PARAMETER_GROUP = BASIC.merge({ + 'ModifyDBParameterGroupResult' => { + 'DBParameterGroupName' => String + } + }) + + DB_PARAMETER = { + 'ParameterValue' => Fog::Nullable::String, + 'DataType' => String, + 'AllowedValues' => Fog::Nullable::String, + 'Source' => String, + 'IsModifiable' => Fog::Boolean, + 'Description' => String, + 'ParameterName' => String, + 'ApplyType' => String + } + + DESCRIBE_DB_PARAMETERS = BASIC.merge({ + 'DescribeDBParametersResult' => { + 'Marker' => Fog::Nullable::String, + 'Parameters' => [DB_PARAMETER] + } + + }) + + DB_LOG_FILE = { + 'LastWritten' => Time, + 'Size' => Integer, + 'LogFileName' => String + } + + DESCRIBE_DB_LOG_FILES = BASIC.merge({ + 'DescribeDBLogFilesResult' => { + 'Marker' => Fog::Nullable::String, + 'DBLogFiles' => [DB_LOG_FILE] + } + }) + + SNAPSHOT = { + 'AllocatedStorage' => Integer, + 'AvailabilityZone' => String, + 'DBInstanceIdentifier' => String, + 'DBSnapshotIdentifier' => String, + 'EngineVersion' => String, + 'Engine' => String, + 'InstanceCreateTime' => Time, + 'Iops' => Fog::Nullable::Integer, + 'MasterUsername' => String, + 'Port' => Integer, + 'SnapshotCreateTime' => Fog::Nullable::Time, + 'Status' => String, + 'SnapshotType' => String + } + + INSTANCE = { + 'AllocatedStorage' => Integer, + 'AutoMinorVersionUpgrade' => Fog::Boolean, + 'AvailabilityZone' => Fog::Nullable::String, + 'BackupRetentionPeriod' => Integer, + 'DBInstanceClass' => String, + 'DBInstanceIdentifier' => String, + 'DBInstanceStatus' => String, + 'DBName' => Fog::Nullable::String, + 'DBParameterGroups' => [{ + 'ParameterApplyStatus' => String, + 'DBParameterGroupName' => String + }], + 'DBSecurityGroups' => [{ + 'Status' => String, + 'DBSecurityGroupName' => String + }], + 'DBSubnetGroupName' => Fog::Nullable::String, + 'PubliclyAccessible' => Fog::Boolean, + 'Endpoint' => { + 'Address' => Fog::Nullable::String, + 'Port' => Fog::Nullable::Integer + }, + 'Engine' => String, + 'EngineVersion' => String, + 'InstanceCreateTime' => Fog::Nullable::Time, + 'Iops' => Fog::Nullable::Integer, + 'LatestRestorableTime' => Fog::Nullable::Time, + 'LicenseModel' => String, + 'MasterUsername' => String, + 'MultiAZ' => Fog::Boolean, + 'PendingModifiedValues' => { + 'BackupRetentionPeriod' => Fog::Nullable::Integer, + 'DBInstanceClass' => Fog::Nullable::String, + 'EngineVersion' => Fog::Nullable::String, + 'MasterUserPassword' => Fog::Nullable::String, + 'MultiAZ' => Fog::Nullable::String, + 'AllocatedStorage' => Fog::Nullable::Integer, + 'Port' => Fog::Nullable::Integer + }, + 'PreferredBackupWindow' => String, + 'PreferredMaintenanceWindow' => String, + 'ReadReplicaDBInstanceIdentifiers' => [Fog::Nullable::String] + } + + REPLICA_INSTANCE = INSTANCE.merge({ + 'BackupRetentionPeriod' => Fog::Nullable::String, + 'PreferredBackupWindow' => Fog::Nullable::String, + 'ReadReplicaSourceDBInstanceIdentifier' => String + }) + + CREATE_DB_INSTANCE = BASIC.merge({ + 'CreateDBInstanceResult' => { + 'DBInstance' => INSTANCE + } + }) + + DESCRIBE_DB_INSTANCES = BASIC.merge({ + 'DescribeDBInstancesResult' => { + 'Marker' => Fog::Nullable::String, + 'DBInstances' => [INSTANCE] + } + }) + + MODIFY_DB_INSTANCE = BASIC.merge({ + 'ModifyDBInstanceResult' => { + 'DBInstance' => INSTANCE + } + }) + + DELETE_DB_INSTANCE = BASIC.merge({ + 'DeleteDBInstanceResult' => { + 'DBInstance' => INSTANCE + } + }) + + REBOOT_DB_INSTANCE = BASIC.merge({ + 'RebootDBInstanceResult' => { + 'DBInstance' => INSTANCE + } + }) + + CREATE_READ_REPLICA = BASIC.merge({ + 'CreateDBInstanceReadReplicaResult' => { + 'DBInstance' => REPLICA_INSTANCE + } + }) + + PROMOTE_READ_REPLICA = BASIC.merge({ + 'PromoteReadReplicaResult' => { + 'DBInstance' => INSTANCE + } + }) + + CREATE_DB_SNAPSHOT = BASIC.merge({ + 'CreateDBSnapshotResult' => { + 'DBSnapshot' => SNAPSHOT + } + }) + + DESCRIBE_DB_SNAPSHOTS = BASIC.merge({ + 'DescribeDBSnapshotsResult' => { + 'Marker' => Fog::Nullable::String, + 'DBSnapshots' => [SNAPSHOT] + } + }) + DELETE_DB_SNAPSHOT = BASIC.merge({ + 'DeleteDBSnapshotResult' => { + 'DBSnapshot' => SNAPSHOT + } + }) + + LIST_TAGS_FOR_RESOURCE = { + 'ListTagsForResourceResult' => { + 'TagList' => Fog::Nullable::Hash + } + } + + EVENT_SUBSCRIPTION = { + 'CustSubscriptionId' => String, + 'EventCategories' => Array, + 'SourceType' => Fog::Nullable::String, + 'Enabled' => String, + 'Status' => String, + 'CreationTime' => Time, + 'SnsTopicArn' => String + } + + CREATE_EVENT_SUBSCRIPTION = { + 'CreateEventSubscriptionResult' => { + 'EventSubscription' => EVENT_SUBSCRIPTION + } + } + + DESCRIBE_EVENT_SUBSCRIPTIONS = { + 'DescribeEventSubscriptionsResult' => { + 'EventSubscriptionsList' => [EVENT_SUBSCRIPTION] + } + } + end + end +end diff --git a/tests/requests/rds/instance_option_tests.rb b/tests/requests/rds/instance_option_tests.rb new file mode 100644 index 000000000..07eced68d --- /dev/null +++ b/tests/requests/rds/instance_option_tests.rb @@ -0,0 +1,21 @@ +Shindo.tests('Aws::RDS | db instance option requests', ['aws', 'rds']) do + tests('success') do + + tests("#describe_orderable_db_instance_options('mysql)").formats(Aws::RDS::Formats::DESCRIBE_ORDERABLE_DB_INSTANCE_OPTION) do + + body = Fog::AWS[:rds].describe_orderable_db_instance_options('mysql').body + + returns(2) {body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].length} + + group = body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].first + returns( true ) { group['MultiAZCapable'] } + returns( 'mysql' ) { group['Engine'] } + returns( true ) { group['ReadReplicaCapable'] } + returns( true ) { group['AvailabilityZones'].length >= 1 } + + body + end + + end + +end diff --git a/tests/requests/rds/instance_tests.rb b/tests/requests/rds/instance_tests.rb new file mode 100644 index 000000000..d44412fc3 --- /dev/null +++ b/tests/requests/rds/instance_tests.rb @@ -0,0 +1,133 @@ +Shindo.tests('Aws::RDS | instance requests', ['aws', 'rds']) do + # Disabled due to https://github.com/fog/fog/1546 + pending + + # random_differentiator + # Useful when rapidly re-running tests, so we don't have to wait + # serveral minutes for deleted servers to disappear + suffix = rand(65536).to_s(16) + + @db_instance_id = "fog-test-#{suffix}" + @db_replica_id = "fog-replica-#{suffix}" + @db_snapshot_id = "fog-snapshot" + @db_final_snapshot_id = "fog-final-snapshot" + + tests('success') do + + tests("#create_db_instance").formats(Aws::RDS::Formats::CREATE_DB_INSTANCE) do + result = Fog::AWS[:rds].create_db_instance(@db_instance_id, + 'AllocatedStorage' => 5, + 'DBInstanceClass' => 'db.m1.small', + 'Engine' => 'mysql', + 'EngineVersion' => '5.1.50', + 'MasterUsername' => 'foguser', + 'BackupRetentionPeriod' => 1, + 'MasterUserPassword' => 'fogpassword').body + + instance = result['CreateDBInstanceResult']['DBInstance'] + returns('creating') { instance['DBInstanceStatus'] } + result + end + + tests("#describe_db_instances").formats(Aws::RDS::Formats::DESCRIBE_DB_INSTANCES) do + Fog::AWS[:rds].describe_db_instances.body + end + + server = Fog::AWS[:rds].servers.get(@db_instance_id) + server.wait_for { ready? } + + new_storage = 6 + tests("#modify_db_instance with immediate apply").formats(Aws::RDS::Formats::MODIFY_DB_INSTANCE) do + body = Fog::AWS[:rds].modify_db_instance(@db_instance_id, true, 'AllocatedStorage' => new_storage).body + tests 'pending storage' do + instance = body['ModifyDBInstanceResult']['DBInstance'] + returns(new_storage) { instance['PendingModifiedValues']['AllocatedStorage'] } + end + body + end + + server.wait_for { state == 'modifying' } + server.wait_for { state == 'available' } + + tests 'new storage' do + returns(new_storage) { server.allocated_storage } + end + + tests("reboot db instance") do + tests("#reboot").formats(Aws::RDS::Formats::REBOOT_DB_INSTANCE) do + Fog::AWS[:rds].reboot_db_instance(@db_instance_id).body + end + end + + server.wait_for { state == 'rebooting' } + server.wait_for { state == 'available' } + + tests("#create_db_snapshot").formats(Aws::RDS::Formats::CREATE_DB_SNAPSHOT) do + body = Fog::AWS[:rds].create_db_snapshot(@db_instance_id, @db_snapshot_id).body + returns('creating') { body['CreateDBSnapshotResult']['DBSnapshot']['Status'] } + body + end + + tests("#describe_db_snapshots").formats(Aws::RDS::Formats::DESCRIBE_DB_SNAPSHOTS) do + body = Fog::AWS[:rds].describe_db_snapshots.body + end + + server.wait_for { state == 'available' } + + tests("#create read replica").formats(Aws::RDS::Formats::CREATE_READ_REPLICA) do + Fog::AWS[:rds].create_db_instance_read_replica(@db_replica_id, @db_instance_id).body + end + + replica = Fog::AWS[:rds].servers.get(@db_replica_id) + replica.wait_for { ready? } + + tests("replica source") do + returns(@db_instance_id) { replica.read_replica_source } + end + server.reload + + tests("replica identifiers") do + returns([@db_replica_id]) { server.read_replica_identifiers } + end + + tests("#promote read replica").formats(Aws::RDS::Formats::PROMOTE_READ_REPLICA) do + Fog::AWS[:rds].promote_read_replica(@db_replica_id).body + end + + tests("#delete_db_instance").formats(Aws::RDS::Formats::DELETE_DB_INSTANCE) do + #server.wait_for { state == 'available' } + Fog::AWS[:rds].delete_db_instance(@db_replica_id, nil, true) + body = Fog::AWS[:rds].delete_db_instance(@db_instance_id, @db_final_snapshot_id).body + + tests "final snapshot" do + returns('creating') { Fog::AWS[:rds].describe_db_snapshots(:snapshot_id => @db_final_snapshot_id).body['DescribeDBSnapshotsResult']['DBSnapshots'].first['Status'] } + end + body + end + + tests("#delete_db_snapshot").formats(Aws::RDS::Formats::DELETE_DB_SNAPSHOT) do + Fog::AWS[:rds].snapshots.get(@db_snapshot_id).wait_for { ready? } + Fog::AWS[:rds].delete_db_snapshot(@db_snapshot_id).body + end + + tests("snapshot.destroy") do + snapshot = Fog::AWS[:rds].snapshots.get(@db_final_snapshot_id) + snapshot.wait_for { ready? } + snapshot.destroy + returns(nil) { Fog::AWS[:rds].snapshots.get(@db_final_snapshot_id) } + end + + end + + tests('failure') do + tests "deleting nonexisting instance" do + raises(Fog::AWS::RDS::NotFound) { Fog::AWS[:rds].delete_db_instance('doesnexist', 'irrelevant') } + end + tests "deleting non existing snapshot" do + raises(Fog::AWS::RDS::NotFound) { Fog::AWS[:rds].delete_db_snapshot('doesntexist') } + end + tests "modifying non existing instance" do + raises(Fog::AWS::RDS::NotFound) { Fog::AWS[:rds].modify_db_instance 'doesntexit', true, 'AllocatedStorage' => 10 } + end + end +end diff --git a/tests/requests/rds/log_file_tests.rb b/tests/requests/rds/log_file_tests.rb new file mode 100644 index 000000000..d5d0a9c04 --- /dev/null +++ b/tests/requests/rds/log_file_tests.rb @@ -0,0 +1,19 @@ +Shindo.tests('Aws::RDS | log file requests', %w[aws rds]) do + tests('success') do + pending if Fog.mocking? + + suffix = rand(65536).to_s(16) + @db_instance_id = "fog-test-#{suffix}" + + tests('#describe_db_log_files').formats(Aws::RDS::Formats::DESCRIBE_DB_LOG_FILES) do + result = Fog::AWS[:rds].describe_db_log_files(@db_instance_id).body['DescribeDBLogFilesResult'] + returns(true) { result['DBLogFiles'].size > 0 } + result + end + + end + + tests('failures') do + raises(Fog::AWS::RDS::NotFound) {Fog::AWS[:rds].describe_db_log_files('doesntexist')} + end +end diff --git a/tests/requests/rds/parameter_group_tests.rb b/tests/requests/rds/parameter_group_tests.rb new file mode 100644 index 000000000..fbe558a7f --- /dev/null +++ b/tests/requests/rds/parameter_group_tests.rb @@ -0,0 +1,62 @@ +Shindo.tests('Aws::RDS | parameter group requests', ['aws', 'rds']) do + tests('success') do + + tests("#create_db_parameter_groups").formats(Aws::RDS::Formats::CREATE_DB_PARAMETER_GROUP) do + body = Fog::AWS[:rds].create_db_parameter_group('fog-group', 'MySQL5.1', 'Some description').body + + returns( 'mysql5.1') { body['CreateDBParameterGroupResult']['DBParameterGroup']['DBParameterGroupFamily']} + returns( 'fog-group') { body['CreateDBParameterGroupResult']['DBParameterGroup']['DBParameterGroupName']} + returns( 'Some description') { body['CreateDBParameterGroupResult']['DBParameterGroup']['Description']} + + body + end + + Fog::AWS[:rds].create_db_parameter_group('other-fog-group', 'MySQL5.1', 'Some description') + + tests("#describe_db_parameter_groups").formats(Aws::RDS::Formats::DESCRIBE_DB_PARAMETER_GROUP) do + + body = Fog::AWS[:rds].describe_db_parameter_groups().body + + returns(4) {body['DescribeDBParameterGroupsResult']['DBParameterGroups'].length} + body + end + + tests("#describe_db_parameter_groups('fog-group)").formats(Aws::RDS::Formats::DESCRIBE_DB_PARAMETER_GROUP) do + + body = Fog::AWS[:rds].describe_db_parameter_groups('fog-group').body + + returns(1) {body['DescribeDBParameterGroupsResult']['DBParameterGroups'].length} + + group = body['DescribeDBParameterGroupsResult']['DBParameterGroups'].first + returns( 'mysql5.1') { group['DBParameterGroupFamily']} + returns( 'fog-group') { group['DBParameterGroupName']} + returns( 'Some description') { group['Description']} + + body + end + + tests("delete_db_parameter_group").formats(Aws::RDS::Formats::BASIC) do + body = Fog::AWS[:rds].delete_db_parameter_group('fog-group').body + + raises(Fog::AWS::RDS::NotFound) {Fog::AWS[:rds].describe_db_parameter_groups('fog-group')} + + body + end + + Fog::AWS[:rds].delete_db_parameter_group('other-fog-group') + end + + tests("failures") do + raises(Fog::AWS::RDS::NotFound) {Fog::AWS[:rds].describe_db_parameter_groups('doesntexist')} + raises(Fog::AWS::RDS::NotFound) {Fog::AWS[:rds].delete_db_parameter_group('doesntexist')} + + tests "creating second group with same id" do + Fog::AWS[:rds].create_db_parameter_group('fog-group', 'MySQL5.1', 'Some description') + raises(Fog::AWS::RDS::IdentifierTaken) {Fog::AWS[:rds].create_db_parameter_group('fog-group', 'MySQL5.1', 'Some description')} + end + + Fog::AWS[:rds].delete_db_parameter_group('fog-group') + + end + +end diff --git a/tests/requests/rds/parameter_request_tests.rb b/tests/requests/rds/parameter_request_tests.rb new file mode 100644 index 000000000..d639a3071 --- /dev/null +++ b/tests/requests/rds/parameter_request_tests.rb @@ -0,0 +1,34 @@ +Shindo.tests('Aws::RDS | parameter requests', ['aws', 'rds']) do + tests('success') do + pending if Fog.mocking? + + Fog::AWS[:rds].create_db_parameter_group('fog-group', 'MySQL5.1', 'Some description') + + tests('#modify_db_parameter_group').formats(Aws::RDS::Formats::MODIFY_PARAMETER_GROUP) do + body = Fog::AWS[:rds].modify_db_parameter_group('fog-group',[ + {'ParameterName' => 'query_cache_size', + 'ParameterValue' => '12345', + 'ApplyMethod' => 'immediate'} + ]).body + + body + end + + tests('#describe_db_parameters').formats(Aws::RDS::Formats::DESCRIBE_DB_PARAMETERS) do + Fog::AWS[:rds].describe_db_parameters('fog-group', :max_records => 20).body + end + + tests("#describe_db_parameters :source => 'user'")do + body = Fog::AWS[:rds].describe_db_parameters('fog-group', :source => 'user').body + returns(1){ body['DescribeDBParametersResult']['Parameters'].length} + + param = body['DescribeDBParametersResult']['Parameters'].first + returns('query_cache_size'){param['ParameterName']} + returns('12345'){param['ParameterValue']} + returns(true){param['IsModifiable']} + returns('query_cache_size'){param['ParameterName']} + end + Fog::AWS[:rds].delete_db_parameter_group('fog-group') + + end +end diff --git a/tests/requests/rds/security_group_tests.rb b/tests/requests/rds/security_group_tests.rb new file mode 100644 index 000000000..951984d0f --- /dev/null +++ b/tests/requests/rds/security_group_tests.rb @@ -0,0 +1,101 @@ +Shindo.tests('Aws::RDS | security group requests', ['aws', 'rds']) do + suffix = rand(65536).to_s(16) + + @sec_group_name = "fog-sec-group-#{suffix}" + if Fog.mocking? + @owner_id = '123456780' + else + @owner_id = Fog::AWS[:rds].security_groups.get('default').owner_id + end + + tests('success') do + + tests("#create_db_security_group").formats(Aws::RDS::Formats::CREATE_DB_SECURITY_GROUP) do + body = Fog::AWS[:rds].create_db_security_group(@sec_group_name, 'Some description').body + + returns( @sec_group_name) { body['CreateDBSecurityGroupResult']['DBSecurityGroup']['DBSecurityGroupName']} + returns( 'Some description') { body['CreateDBSecurityGroupResult']['DBSecurityGroup']['DBSecurityGroupDescription']} + returns( []) { body['CreateDBSecurityGroupResult']['DBSecurityGroup']['EC2SecurityGroups']} + returns( []) { body['CreateDBSecurityGroupResult']['DBSecurityGroup']['IPRanges']} + + body + end + + tests("#describe_db_security_groups").formats(Aws::RDS::Formats::DESCRIBE_DB_SECURITY_GROUP) do + Fog::AWS[:rds].describe_db_security_groups.body + end + + tests("#authorize_db_security_group_ingress CIDR").formats(Aws::RDS::Formats::AUTHORIZE_DB_SECURITY_GROUP) do + @cidr = '0.0.0.0/0' + body = Fog::AWS[:rds].authorize_db_security_group_ingress(@sec_group_name,{'CIDRIP'=>@cidr}).body + + returns("authorizing") { body['AuthorizeDBSecurityGroupIngressResult']['DBSecurityGroup']['IPRanges'].find{|h| h['CIDRIP'] == @cidr}['Status']} + body + end + + sec_group = Fog::AWS[:rds].security_groups.get(@sec_group_name) + sec_group.wait_for {ready?} + + tests("#authorize_db_security_group_ingress another CIDR").formats(Aws::RDS::Formats::AUTHORIZE_DB_SECURITY_GROUP) do + @cidr = "10.0.0.0/24" + body = Fog::AWS[:rds].authorize_db_security_group_ingress(@sec_group_name,{'CIDRIP'=>@cidr}).body + + returns("authorizing") { body['AuthorizeDBSecurityGroupIngressResult']['DBSecurityGroup']['IPRanges'].find{|h| h['CIDRIP'] == @cidr}['Status']} + body + end + + sec_group = Fog::AWS[:rds].security_groups.get(@sec_group_name) + sec_group.wait_for {ready?} + + tests("#count CIDRIP").formats(Aws::RDS::Formats::DESCRIBE_DB_SECURITY_GROUP) do + body = Fog::AWS[:rds].describe_db_security_groups(@sec_group_name).body + returns(2) { body['DescribeDBSecurityGroupsResult']['DBSecurityGroups'][0]['IPRanges'].size } + body + end + + tests("#revoke_db_security_group_ingress CIDR").formats(Aws::RDS::Formats::REVOKE_DB_SECURITY_GROUP) do + @cidr = '0.0.0.0/0' + body = Fog::AWS[:rds].revoke_db_security_group_ingress(@sec_group_name,{'CIDRIP'=> @cidr}).body + returns("revoking") { body['RevokeDBSecurityGroupIngressResult']['DBSecurityGroup']['IPRanges'].find{|h| h['CIDRIP'] == @cidr}['Status']} + body + end + + tests("#authorize_db_security_group_ingress EC2").formats(Aws::RDS::Formats::AUTHORIZE_DB_SECURITY_GROUP) do + @ec2_sec_group = 'default' + body = Fog::AWS[:rds].authorize_db_security_group_ingress(@sec_group_name,{'EC2SecurityGroupName' => @ec2_sec_group, 'EC2SecurityGroupOwnerId' => @owner_id}).body + + returns("authorizing") { body['AuthorizeDBSecurityGroupIngressResult']['DBSecurityGroup']['EC2SecurityGroups'].find{|h| h['EC2SecurityGroupName'] == @ec2_sec_group}['Status']} + returns(@owner_id) { body['AuthorizeDBSecurityGroupIngressResult']['DBSecurityGroup']['EC2SecurityGroups'].find{|h| h['EC2SecurityGroupName'] == @ec2_sec_group}['EC2SecurityGroupOwnerId']} + body + end + + tests("duplicate #authorize_db_security_group_ingress EC2").raises(Fog::AWS::RDS::AuthorizationAlreadyExists) do + @ec2_sec_group = 'default' + + Fog::AWS[:rds].authorize_db_security_group_ingress(@sec_group_name,{'EC2SecurityGroupName' => @ec2_sec_group, 'EC2SecurityGroupOwnerId' => @owner_id}) + end + + sec_group = Fog::AWS[:rds].security_groups.get(@sec_group_name) + sec_group.wait_for {ready?} + + tests("#revoke_db_security_group_ingress EC2").formats(Aws::RDS::Formats::REVOKE_DB_SECURITY_GROUP) do + @ec2_sec_group = 'default' + + body = Fog::AWS[:rds].revoke_db_security_group_ingress(@sec_group_name,{'EC2SecurityGroupName' => @ec2_sec_group, 'EC2SecurityGroupOwnerId' => @owner_id}).body + + returns("revoking") { body['RevokeDBSecurityGroupIngressResult']['DBSecurityGroup']['EC2SecurityGroups'].find{|h| h['EC2SecurityGroupName'] == @ec2_sec_group}['Status']} + body + end + + + #TODO, authorize ec2 security groups + + tests("#delete_db_security_group").formats(Aws::RDS::Formats::BASIC) do + body = Fog::AWS[:rds].delete_db_security_group(@sec_group_name).body + + raises(Fog::AWS::RDS::NotFound) {Fog::AWS[:rds].describe_db_security_groups(@sec_group_name)} + + body + end + end +end diff --git a/tests/requests/rds/subnet_groups_tests.rb b/tests/requests/rds/subnet_groups_tests.rb new file mode 100644 index 000000000..0763019a3 --- /dev/null +++ b/tests/requests/rds/subnet_groups_tests.rb @@ -0,0 +1,52 @@ +Shindo.tests('Aws::RDS | subnet group requests', ['aws', 'rds']) do + # random_differentiator + # Useful when rapidly re-running tests, so we don't have to wait + # serveral minutes for deleted VPCs/subnets to disappear + suffix = rand(65536).to_s(16) + @subnet_group_name = "fog-test-#{suffix}" + + vpc_range = rand(245) + 10 + @vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => "10.#{vpc_range}.0.0/16") + + # Create 4 subnets in this VPC, each one in a different AZ + subnet_az = 'us-east-1a' + subnet_range = 8 + @subnets = (1..4).map do + subnet = Fog::Compute[:aws].create_subnet(@vpc.id, "10.#{vpc_range}.#{subnet_range}.0/24", + 'AvailabilityZone' => subnet_az).body['subnet'] + subnet_az = subnet_az.succ + subnet_range *= 2 + subnet + end + + tests('success') do + + subnet_ids = @subnets.map { |sn| sn['subnetId'] }.to_a + + tests("#create_db_subnet_group").formats(Aws::RDS::Formats::CREATE_DB_SUBNET_GROUP) do + result = Fog::AWS[:rds].create_db_subnet_group(@subnet_group_name, subnet_ids, 'A subnet group').body + + returns(@subnet_group_name) { result['CreateDBSubnetGroupResult']['DBSubnetGroup']['DBSubnetGroupName'] } + returns('A subnet group') { result['CreateDBSubnetGroupResult']['DBSubnetGroup']['DBSubnetGroupDescription'] } + returns(@vpc.id) { result['CreateDBSubnetGroupResult']['DBSubnetGroup']['VpcId'] } + returns(subnet_ids.sort) { result['CreateDBSubnetGroupResult']['DBSubnetGroup']['Subnets'].sort } + + result + end + + tests("#describe_db_subnet_groups").formats(Aws::RDS::Formats::DESCRIBE_DB_SUBNET_GROUPS) do + Fog::AWS[:rds].describe_db_subnet_groups.body + end + + tests("#delete_db_subnet_group").formats(Aws::RDS::Formats::BASIC) do + Fog::AWS[:rds].delete_db_subnet_group(@subnet_group_name).body + end + + end + + @subnets.each do |sn| + Fog::Compute[:aws].delete_subnet(sn['subnetId']) + end + @vpc.destroy + +end diff --git a/tests/requests/rds/tagging_tests.rb b/tests/requests/rds/tagging_tests.rb new file mode 100644 index 000000000..6ad943207 --- /dev/null +++ b/tests/requests/rds/tagging_tests.rb @@ -0,0 +1,78 @@ +Shindo.tests('Aws::RDS | tagging requests', ['aws', 'rds']) do + @rds = Fog::AWS[:rds] + @db_instance_id = "fog-test-#{rand(65536).to_s(16)}" + Formatador.display_line "Creating RDS instance #{@db_instance_id}" + @rds.create_db_instance(@db_instance_id, 'AllocatedStorage' => 5, + 'DBInstanceClass' => 'db.t1.micro', 'Engine' => 'mysql', + 'MasterUsername' => 'foguser', 'MasterUserPassword' => 'fogpassword') + Formatador.display_line "Waiting for instance #{@db_instance_id} to be ready" + @db = @rds.servers.get(@db_instance_id) + @db.wait_for { ready? } + + tests('success') do + + single_tag = {'key1' => 'value1'} + two_tags = {'key2' => 'value2', 'key3' => 'value3'} + + tests("#add_tags_to_resource with a single tag"). + formats(Aws::RDS::Formats::BASIC) do + result = @rds.add_tags_to_resource(@db_instance_id, single_tag).body + returns(single_tag) do + @rds.list_tags_for_resource(@db_instance_id). + body['ListTagsForResourceResult']['TagList'] + end + result + end + + tests("#add_tags_to_resource with a multiple tags"). + formats(Aws::RDS::Formats::BASIC) do + result = @rds.add_tags_to_resource(@db_instance_id, two_tags).body + returns(single_tag.merge(two_tags)) do + @rds.list_tags_for_resource(@db_instance_id). + body['ListTagsForResourceResult']['TagList'] + end + result + end + + tests("#remove_tags_from_resource").formats(Aws::RDS::Formats::BASIC) do + result = @rds.remove_tags_from_resource( + @db_instance_id, single_tag.keys).body + returns(two_tags) do + @rds.list_tags_for_resource(@db_instance_id). + body['ListTagsForResourceResult']['TagList'] + end + result + end + + tests("#list_tags_for_resource"). + formats(Aws::RDS::Formats::LIST_TAGS_FOR_RESOURCE) do + result = @rds.list_tags_for_resource(@db_instance_id).body + returns(two_tags) do + result['ListTagsForResourceResult']['TagList'] + end + result + end + + end + + tests('failure') do + tests "tagging a nonexisting instance" do + raises(Fog::AWS::RDS::NotFound) do + @rds.add_tags_to_resource('doesnexist', {'key1' => 'value1'}) + end + end + tests "listing tags for a nonexisting instance" do + raises(Fog::AWS::RDS::NotFound) do + @rds.list_tags_for_resource('doesnexist') + end + end + tests "removing tags for a nonexisting instance" do + raises(Fog::AWS::RDS::NotFound) do + @rds.remove_tags_from_resource('doesnexist', ['key1']) + end + end + end + + Formatador.display_line "Destroying DB instance #{@db_instance_id}" + @db.destroy +end diff --git a/tests/requests/redshift/cluster_parameter_group_tests.rb b/tests/requests/redshift/cluster_parameter_group_tests.rb new file mode 100644 index 000000000..c7f43602f --- /dev/null +++ b/tests/requests/redshift/cluster_parameter_group_tests.rb @@ -0,0 +1,76 @@ +Shindo.tests('Fog::Redshift[:aws] | cluster parameter group requests', ['aws']) do + pending if Fog.mocking? + suffix = rand(65536).to_s(16) + parameter_group = "test-cluster-parameter-group-#{suffix}" + + @cluster_parameter_format = { + 'Parameter' => { + "ParameterValue" => String, + "DataType" => String, + "Source" => String, + "IsModifiable" => Fog::Boolean, + "Description" => String, + "ParameterName" => String + } + } + + @cluster_parameters_format = { + "Parameters"=> [@cluster_parameter_format] + } + + @cluster_parameter_group_format = { + 'ClusterParameterGroup' => { + "ParameterGroupFamily" => String, + "Description" => String, + "ParameterGroupName" => String + } + } + + @cluster_parameter_groups_format = { + "ParameterGroups"=> [@cluster_parameter_group_format] + } + + @modify_cluster_parameter_group_format = { + "ParameterGroupStatus" => String, + "ParameterGroupName" => String + } + + tests('success') do + tests("create_cluster_parameter_group").formats(@cluster_parameter_group_format) do + body = Fog::AWS[:redshift].create_cluster_parameter_group(:parameter_group_name=> parameter_group, + :parameter_group_family=>"redshift-1.0", + :description=>'testing').body + body + end + + tests("describe_cluster_parameter_groups").formats(@cluster_parameter_groups_format) do + body = Fog::AWS[:redshift].describe_cluster_parameter_groups.body + body + end + + tests("describe_cluster_parameters").formats(@cluster_parameters_format) do + body = Fog::AWS[:redshift].describe_cluster_parameters(:parameter_group_name=>parameter_group).body + body + end + + tests("modify_cluster_parameter_groups").formats(@modify_cluster_parameter_group_format) do + body = Fog::AWS[:redshift].modify_cluster_parameter_group(:parameter_group_name=>parameter_group, + :parameters=>{ + :parameter_name=>'extra_float_digits', + :parameter_value=>2}).body + body + end + + tests("delete_cluster_parameter_group") do + present = !Fog::AWS[:redshift].describe_cluster_parameter_groups(:parameter_group_name=>parameter_group).body['ParameterGroups'].empty? + tests("verify presence before deletion").returns(true) { present } + + Fog::AWS[:redshift].delete_cluster_parameter_group(:parameter_group_name=>parameter_group) + + not_present = Fog::AWS[:redshift].describe_cluster_parameter_groups(:parameter_group_name=>parameter_group).body['ParameterGroups'].empty? + tests("verify deletion").returns(true) { not_present } + end + + end + +end diff --git a/tests/requests/redshift/cluster_security_group_tests.rb b/tests/requests/redshift/cluster_security_group_tests.rb new file mode 100644 index 000000000..698268369 --- /dev/null +++ b/tests/requests/redshift/cluster_security_group_tests.rb @@ -0,0 +1,42 @@ +Shindo.tests('Fog::Redshift[:aws] | cluster security group requests', ['aws']) do + pending if Fog.mocking? + suffix = rand(65536).to_s(16) + identifier = "test-cluster-security-group-#{suffix}" + + @cluster_security_group_format = { + "ClusterSecurityGroup" => { + "EC2SecurityGroups" => Fog::Nullable::Array, + "IPRanges" => Fog::Nullable::Array, + "Description" => String, + "ClusterSecurityGroupName" => String + } + } + + @describe_cluster_security_groups_format = { + "ClusterSecurityGroups" => [@cluster_security_group_format] + } + + tests('success') do + tests("create_cluster_security_group").formats(@cluster_security_group_format) do + body = Fog::AWS[:redshift].create_cluster_security_group(:cluster_security_group_name => identifier, :description => 'testing').body + body + end + + tests("describe_cluster_security_groups").formats(@describe_cluster_security_groups_format) do + body = Fog::AWS[:redshift].describe_cluster_security_groups.body + body + end + + tests("delete_cluster_security_group") do + present = !Fog::AWS[:redshift].describe_cluster_security_groups(:cluster_security_group_name => identifier).body['ClusterSecurityGroups'].empty? + tests("verify presence before deletion").returns(true) { present } + + Fog::AWS[:redshift].delete_cluster_security_group(:cluster_security_group_name => identifier) + + not_present = Fog::AWS[:redshift].describe_cluster_security_groups(:cluster_security_group_name => identifier).body['ClusterSecurityGroups'].empty? + tests("verify deletion").returns(true) { not_present } + end + + end + +end diff --git a/tests/requests/redshift/cluster_snapshot_tests.rb b/tests/requests/redshift/cluster_snapshot_tests.rb new file mode 100644 index 000000000..7365411fe --- /dev/null +++ b/tests/requests/redshift/cluster_snapshot_tests.rb @@ -0,0 +1,73 @@ +Shindo.tests('Fog::Redshift[:aws] | cluster snapshot requests', ['aws']) do + pending if Fog.mocking? + suffix = rand(65536).to_s(16) + identifier = "test-snapshot-#{suffix}" + cluster = "test-cluster-#{suffix}" + start_time = Fog::Time.now.to_iso8601_basic + @cluster_snapshot_format = { + 'Snapshot' => { + "AccountsWithRestoreAccess" => Fog::Nullable::Array, + "Port" => Integer, + "SnapshotIdentifier" => String, + "OwnerAccount" => String, + "Status" => String, + "SnapshotType" => String, + "ClusterVersion" => String, + "EstimatedSecondsToCompletion" => Integer, + "SnapshotCreateTime" => Time, + "Encrypted" => Fog::Boolean, + "NumberOfNodes" => Integer, + "DBName" => String, + "CurrentBackupRateInMegaBytesPerSecond" => Float, + "ClusterCreateTime" => Time, + "AvailabilityZone" => String, + "ActualIncrementalBackupSizeInMegaBytes" => Float, + "TotalBackupSizeInMegaBytes" => Float, + "ElapsedTimeInSeconds" => Integer, + "BackupProgressInMegaBytes" => Float, + "NodeType" => String, + "ClusterIdentifier" => String, + "MasterUsername" => String + } + } + + @describe_cluster_snapshots_format = { + "Snapshots" => [@cluster_snapshot_format] + } + + tests('success') do + tests("create_cluster_snapshot").formats(@cluster_snapshot_format) do + Fog::AWS[:redshift].create_cluster(:cluster_identifier => cluster, + :master_user_password => 'Pass1234', + :master_username => 'testuser', + :node_type => 'dw.hs1.xlarge', + :cluster_type => 'single-node') + Fog.wait_for do + "available" == Fog::AWS[:redshift].describe_clusters(:cluster_identifier=>cluster).body['ClusterSet'].first['Cluster']['ClusterStatus'] + end + body = Fog::AWS[:redshift].create_cluster_snapshot(:snapshot_identifier => identifier, + :cluster_identifier => cluster).body + body + end + + tests('describe_cluster_snaphots').formats(@describe_cluster_snapshots_format) do + sleep 30 unless Fog.mocking? + body = Fog::AWS[:redshift].describe_cluster_snapshots(:start_time=>start_time).body + body + end + + tests('delete_cluster_snapshot').formats(@cluster_snapshot_format) do + Fog.wait_for do + "available" == Fog::AWS[:redshift].describe_cluster_snapshots(:snapshot_identifier=>identifier).body['Snapshots'].first['Snapshot']['Status'] + end + sleep 30 unless Fog.mocking? + body = Fog::AWS[:redshift].delete_cluster_snapshot(:snapshot_identifier=>identifier).body + body + end + + Fog::AWS[:redshift].delete_cluster(:cluster_identifier => cluster, + :skip_final_cluster_snapshot => true) + + end + +end diff --git a/tests/requests/redshift/cluster_tests.rb b/tests/requests/redshift/cluster_tests.rb new file mode 100644 index 000000000..27d1ded7d --- /dev/null +++ b/tests/requests/redshift/cluster_tests.rb @@ -0,0 +1,80 @@ +Shindo.tests('Fog::Redshift[:aws] | cluster requests', ['aws']) do + pending if Fog.mocking? + identifier = "test-cluster-#{rand(65536).to_s(16)}" + + @cluster_format = { + 'Cluster' => { + "ClusterParameterGroups" => [{ + "ClusterParameterGroup" => { + "ParameterApplyStatus" => String, + "ParameterGroupName" => String + } + }], + "ClusterSecurityGroups" => [{ + 'ClusterSecurityGroup' => { + "Status" => String, + "ClusterSecurityGroupName" => String + } + }], + "VpcSecurityGroups" => Fog::Nullable::Array, + "EndPoint" => Fog::Nullable::Hash, + "PendingModifiedValues" => Fog::Nullable::Hash, + "RestoreStatus" => Fog::Nullable::Hash, + "ClusterVersion" => String, + "ClusterStatus" => String, + "Encrypted" => Fog::Boolean, + "NumberOfNodes" => Integer, + "PubliclyAccessible" => Fog::Boolean, + "AutomatedSnapshotRetentionPeriod" => Integer, + "DBName" => String, + "PreferredMaintenanceWindow" => String, + "NodeType" => String, + "ClusterIdentifier" => String, + "AllowVersionUpgrade" => Fog::Boolean, + "MasterUsername" => String + } + } + @describe_clusters_format = { + "ClusterSet" => [{ + 'Cluster' => @cluster_format['Cluster'].merge({"ClusterCreateTime"=>Time, "AvailabilityZone"=>String, "EndPoint"=>{"Port"=>Integer, "Address"=>String}}) + }] + } + + tests('success') do + tests('create_cluster').formats(@cluster_format) do + body = Fog::AWS[:redshift].create_cluster(:cluster_identifier => identifier, + :master_user_password => 'Password1234', + :master_username => 'testuser', + :node_type => 'dw.hs1.xlarge', + :cluster_type => 'single-node').body + Fog.wait_for do + "available" == Fog::AWS[:redshift].describe_clusters(:cluster_identifier=>identifier).body['ClusterSet'].first['Cluster']['ClusterStatus'] + end + body + end + + tests('describe_clusters').formats(@describe_clusters_format["ClusterSet"]) do + sleep 30 unless Fog.mocking? + body = Fog::AWS[:redshift].describe_clusters(:cluster_identifier=>identifier).body["ClusterSet"] + body + end + + tests('reboot_cluster') do + sleep 30 unless Fog.mocking? + body = Fog::AWS[:redshift].reboot_cluster(:cluster_identifier=>identifier).body + tests("verify reboot").returns("rebooting") { body['Cluster']['ClusterStatus']} + body + end + + tests('delete_cluster') do + Fog.wait_for do + "available" == Fog::AWS[:redshift].describe_clusters(:cluster_identifier=>identifier).body['ClusterSet'].first['Cluster']['ClusterStatus'] + end + sleep 30 unless Fog.mocking? + body = Fog::AWS[:redshift].delete_cluster(:cluster_identifier=>identifier, :skip_final_cluster_snapshot=>true).body + tests("verify delete").returns("deleting") { body['Cluster']['ClusterStatus']} + body + end + end + +end diff --git a/tests/requests/ses/helper.rb b/tests/requests/ses/helper.rb new file mode 100644 index 000000000..8d773c101 --- /dev/null +++ b/tests/requests/ses/helper.rb @@ -0,0 +1,9 @@ +class Aws + module SES + module Formats + BASIC = { + 'ResponseMetadata' => {'RequestId' => String} + } + end + end +end diff --git a/tests/requests/ses/verified_domain_identity_tests.rb b/tests/requests/ses/verified_domain_identity_tests.rb new file mode 100644 index 000000000..91392d9cf --- /dev/null +++ b/tests/requests/ses/verified_domain_identity_tests.rb @@ -0,0 +1,16 @@ +Shindo.tests('Aws::SES | verified domain identity requests', ['aws', 'ses']) do + + tests('success') do + + tests("#verify_domain_identity('example.com')").formats(Aws::SES::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:ses].verify_domain_identity('example.com').body + end + + end + + tests('failure') do + + end + +end diff --git a/tests/requests/ses/verified_email_address_tests.rb b/tests/requests/ses/verified_email_address_tests.rb new file mode 100644 index 000000000..8f8860bf1 --- /dev/null +++ b/tests/requests/ses/verified_email_address_tests.rb @@ -0,0 +1,27 @@ +Shindo.tests('Aws::SES | verified email address requests', ['aws', 'ses']) do + + tests('success') do + + tests("#verify_email_address('test@example.com')").formats(Aws::SES::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:ses].verify_email_address('test@example.com').body + end + + tests("#list_verified_email_addresses").formats(Aws::SES::Formats::BASIC.merge('VerifiedEmailAddresses' => [String])) do + pending if Fog.mocking? + Fog::AWS[:ses].list_verified_email_addresses.body + end + + # email won't be there to delete, but succeeds regardless + tests("#delete_verified_email_address('test@example.com')").formats(Aws::SES::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:ses].delete_verified_email_address('notaanemail@example.com').body + end + + end + + tests('failure') do + + end + +end diff --git a/tests/requests/simpledb/attributes_tests.rb b/tests/requests/simpledb/attributes_tests.rb new file mode 100644 index 000000000..6075352de --- /dev/null +++ b/tests/requests/simpledb/attributes_tests.rb @@ -0,0 +1,86 @@ +Shindo.tests('Aws::SimpleDB | attributes requests', ['aws']) do + + @domain_name = "fog_domain_#{Time.now.to_f.to_s.gsub('.','')}" + + Fog::AWS[:simpledb].create_domain(@domain_name) + + tests('success') do + + tests("#batch_put_attributes('#{@domain_name}', { 'a' => { 'b' => 'c', 'd' => 'e' }, 'x' => { 'y' => 'z' } }).body").formats(Aws::SimpleDB::Formats::BASIC) do + Fog::AWS[:simpledb].batch_put_attributes(@domain_name, { 'a' => { 'b' => 'c', 'd' => 'e' }, 'x' => { 'y' => 'z' } }).body + end + + tests("#get_attributes('#{@domain_name}', 'a', {'ConsistentRead' => true}).body['Attributes']").returns({'b' => ['c'], 'd' => ['e']}) do + Fog::AWS[:simpledb].get_attributes(@domain_name, 'a', {'ConsistentRead' => true}).body['Attributes'] + end + + tests("#get_attributes('#{@domain_name}', 'AttributeName' => 'notanattribute')").succeeds do + Fog::AWS[:simpledb].get_attributes(@domain_name, 'AttributeName' => 'notanattribute') + end + + tests("#select('select * from #{@domain_name}', {'ConsistentRead' => true}).body['Items']").returns({'a' => { 'b' => ['c'], 'd' => ['e']}, 'x' => { 'y' => ['z'] } }) do + pending if Fog.mocking? + Fog::AWS[:simpledb].select("select * from #{@domain_name}", {'ConsistentRead' => true}).body['Items'] + end + + tests("#put_attributes('#{@domain_name}', 'conditional', { 'version' => '1' }).body").formats(Aws::SimpleDB::Formats::BASIC) do + Fog::AWS[:simpledb].put_attributes(@domain_name, 'conditional', { 'version' => '1' }).body + end + + tests("#put_attributes('#{@domain_name}', 'conditional', { 'version' => '2' }, :expect => { 'version' => '1' }, :replace => ['version']).body").formats(Aws::SimpleDB::Formats::BASIC) do + Fog::AWS[:simpledb].put_attributes(@domain_name, 'conditional', { 'version' => '2' }, :expect => { 'version' => '1' }, :replace => ['version']).body + end + + # Verify that we can delete individual attributes. + tests("#delete_attributes('#{@domain_name}', 'a', {'d' => []})").succeeds do + Fog::AWS[:simpledb].delete_attributes(@domain_name, 'a', {'d' => []}).body + end + + # Verify that individually deleted attributes are actually removed. + tests("#get_attributes('#{@domain_name}', 'a', {'AttributeName' => ['d'], 'ConsistentRead' => true}).body['Attributes']").returns({}) do + Fog::AWS[:simpledb].get_attributes(@domain_name, 'a', {'AttributeName' => ['d'], 'ConsistentRead' => true}).body['Attributes'] + end + + tests("#delete_attributes('#{@domain_name}', 'a').body").formats(Aws::SimpleDB::Formats::BASIC) do + Fog::AWS[:simpledb].delete_attributes(@domain_name, 'a').body + end + + # Verify that we can delete entire domain, item combinations. + tests("#delete_attributes('#{@domain_name}', 'a').body").succeeds do + Fog::AWS[:simpledb].delete_attributes(@domain_name, 'a').body + end + + # Verify that deleting a domain, item combination removes all related attributes. + tests("#get_attributes('#{@domain_name}', 'a', {'ConsistentRead' => true}).body['Attributes']").returns({}) do + Fog::AWS[:simpledb].get_attributes(@domain_name, 'a', {'ConsistentRead' => true}).body['Attributes'] + end + + end + + tests('failure') do + + tests("#batch_put_attributes('notadomain', { 'a' => { 'b' => 'c' }, 'x' => { 'y' => 'z' } })").raises(Excon::Errors::BadRequest) do + Fog::AWS[:simpledb].batch_put_attributes('notadomain', { 'a' => { 'b' => 'c' }, 'x' => { 'y' => 'z' } }) + end + + tests("#get_attributes('notadomain', 'a')").raises(Excon::Errors::BadRequest) do + Fog::AWS[:simpledb].get_attributes('notadomain', 'a') + end + + tests("#put_attributes('notadomain', 'conditional', { 'version' => '1' })").raises(Excon::Errors::BadRequest) do + Fog::AWS[:simpledb].put_attributes('notadomain', 'foo', { 'version' => '1' }) + end + + tests("#put_attributes('#{@domain_name}', 'conditional', { 'version' => '2' }, :expect => { 'version' => '1' }, :replace => ['version'])").raises(Excon::Errors::Conflict) do + Fog::AWS[:simpledb].put_attributes(@domain_name, 'conditional', { 'version' => '2' }, :expect => { 'version' => '1' }, :replace => ['version']) + end + + tests("#delete_attributes('notadomain', 'a')").raises(Excon::Errors::BadRequest) do + Fog::AWS[:simpledb].delete_attributes('notadomain', 'a') + end + + end + + Fog::AWS[:simpledb].delete_domain(@domain_name) + +end diff --git a/tests/requests/simpledb/domain_tests.rb b/tests/requests/simpledb/domain_tests.rb new file mode 100644 index 000000000..52be3c5f9 --- /dev/null +++ b/tests/requests/simpledb/domain_tests.rb @@ -0,0 +1,51 @@ +Shindo.tests('Aws::SimpleDB | domain requests', ['aws']) do + + @domain_metadata_format = Aws::SimpleDB::Formats::BASIC.merge({ + 'AttributeNameCount' => Integer, + 'AttributeNamesSizeBytes' => Integer, + 'AttributeValueCount' => Integer, + 'AttributeValuesSizeBytes' => Integer, + 'ItemCount' => Integer, + 'ItemNamesSizeBytes' => Integer, + 'Timestamp' => Time + }) + + @domain_name = "fog_domain_#{Time.now.to_f.to_s.gsub('.','')}" + + tests('success') do + + tests("#create_domain(#{@domain_name})").formats(Aws::SimpleDB::Formats::BASIC) do + Fog::AWS[:simpledb].create_domain(@domain_name).body + end + + tests("#create_domain(#{@domain_name})").succeeds do + Fog::AWS[:simpledb].create_domain(@domain_name) + end + + tests("#domain_metadata(#{@domain_name})").formats(@domain_metadata_format) do + Fog::AWS[:simpledb].domain_metadata(@domain_name).body + end + + tests("#list_domains").formats(Aws::SimpleDB::Formats::BASIC.merge('Domains' => [String])) do + Fog::AWS[:simpledb].list_domains.body + end + + tests("#delete_domain(#{@domain_name})").formats(Aws::SimpleDB::Formats::BASIC) do + Fog::AWS[:simpledb].delete_domain(@domain_name).body + end + + tests("#delete_domain(#{@domain_name})").succeeds do + Fog::AWS[:simpledb].delete_domain(@domain_name) + end + + end + + tests('failure') do + + tests("#domain_metadata('notadomain')").raises(Excon::Errors::BadRequest) do + Fog::AWS[:simpledb].domain_metadata('notadomain') + end + + end + +end diff --git a/tests/requests/simpledb/helper.rb b/tests/requests/simpledb/helper.rb new file mode 100644 index 000000000..d29de6275 --- /dev/null +++ b/tests/requests/simpledb/helper.rb @@ -0,0 +1,10 @@ +class Aws + module SimpleDB + module Formats + BASIC = { + 'BoxUsage' => Float, + 'RequestId' => String + } + end + end +end diff --git a/tests/requests/sns/helper.rb b/tests/requests/sns/helper.rb new file mode 100644 index 000000000..efc06c84d --- /dev/null +++ b/tests/requests/sns/helper.rb @@ -0,0 +1,9 @@ +class Aws + module SNS + module Formats + BASIC = { + 'RequestId' => String + } + end + end +end diff --git a/tests/requests/sns/subscription_tests.rb b/tests/requests/sns/subscription_tests.rb new file mode 100644 index 000000000..3c8caca9c --- /dev/null +++ b/tests/requests/sns/subscription_tests.rb @@ -0,0 +1,86 @@ +Shindo.tests('Aws::SES | topic lifecycle tests', ['aws', 'sns']) do + + unless Fog.mocking? + @topic_arn = Fog::AWS[:sns].create_topic('fog_subscription_tests').body['TopicArn'] + @queue_url = Fog::AWS[:sqs].create_queue('fog_subscription_tests').body['QueueUrl'] + @queue_arn = Fog::AWS[:sqs].get_queue_attributes(@queue_url, 'QueueArn').body['Attributes']['QueueArn'] + Fog::AWS[:sqs].set_queue_attributes( + @queue_url, + 'Policy', + Fog::JSON.encode({ + 'Id' => @topic_arn, + 'Statement' => { + 'Action' => 'sqs:SendMessage', + 'Condition' => { + 'StringEquals' => { 'aws:SourceArn' => @topic_arn } + }, + 'Effect' => 'Allow', + 'Principal' => { 'Aws' => '*' }, + 'Resource' => @queue_arn, + 'Sid' => "#{@topic_arn}+sqs:SendMessage" + }, + 'Version' => '2008-10-17' + }) + ) + end + + tests('success') do + + tests("#subscribe('#{@topic_arn}', '#{@queue_arn}', 'sqs')").formats(Aws::SNS::Formats::BASIC.merge('SubscriptionArn' => String)) do + pending if Fog.mocking? + body = Fog::AWS[:sns].subscribe(@topic_arn, @queue_arn, 'sqs').body + @subscription_arn = body['SubscriptionArn'] + body + end + + list_subscriptions_format = Aws::SNS::Formats::BASIC.merge({ + 'Subscriptions' => [{ + 'Endpoint' => String, + 'Owner' => String, + 'Protocol' => String, + 'SubscriptionArn' => String, + 'TopicArn' => String + }] + }) + + tests("#list_subscriptions").formats(list_subscriptions_format) do + pending if Fog.mocking? + Fog::AWS[:sns].list_subscriptions.body + end + + tests("#list_subscriptions_by_topic('#{@topic_arn}')").formats(list_subscriptions_format) do + pending if Fog.mocking? + body = Fog::AWS[:sns].list_subscriptions_by_topic(@topic_arn).body + end + + tests("#publish('#{@topic_arn}', 'message')").formats(Aws::SNS::Formats::BASIC.merge('MessageId' => String)) do + pending if Fog.mocking? + body = Fog::AWS[:sns].publish(@topic_arn, 'message').body + end + + tests("#receive_message('#{@queue_url}')...").returns('message') do + pending if Fog.mocking? + message = nil + Fog.wait_for do + message = Fog::AWS[:sqs].receive_message(@queue_url).body['Message'].first + end + Fog::JSON.decode(message['Body'])['Message'] + end + + tests("#unsubscribe('#{@subscription_arn}')").formats(Aws::SNS::Formats::BASIC) do + pending if Fog.mocking? + Fog::AWS[:sns].unsubscribe(@subscription_arn).body + end + + end + + tests('failure') do + + end + + unless Fog.mocking? + Fog::AWS[:sns].delete_topic(@topic_arn) + Fog::AWS[:sqs].delete_queue(@queue_url) + end + +end diff --git a/tests/requests/sns/topic_tests.rb b/tests/requests/sns/topic_tests.rb new file mode 100644 index 000000000..671b6c34e --- /dev/null +++ b/tests/requests/sns/topic_tests.rb @@ -0,0 +1,45 @@ +Shindo.tests('Aws::SNS | topic lifecycle tests', ['aws', 'sns']) do + + tests('success') do + + tests("#create_topic('fog_topic_tests')").formats(Aws::SNS::Formats::BASIC.merge('TopicArn' => String)) do + body = Fog::AWS[:sns].create_topic('fog_topic_tests').body + @topic_arn = body["TopicArn"] + body + end + + tests("#list_topics").formats(Aws::SNS::Formats::BASIC.merge('Topics' => [String])) do + Fog::AWS[:sns].list_topics.body + end + + tests("#set_topic_attributes('#{@topic_arn}', 'DisplayName', 'other-fog_topic_tests')").formats(Aws::SNS::Formats::BASIC) do + Fog::AWS[:sns].set_topic_attributes(@topic_arn, 'DisplayName', 'other-fog_topic_tests').body + end + + get_topic_attributes_format = Aws::SNS::Formats::BASIC.merge({ + 'Attributes' => { + 'DisplayName' => String, + 'Owner' => String, + 'Policy' => String, + 'SubscriptionsConfirmed' => Integer, + 'SubscriptionsDeleted' => Integer, + 'SubscriptionsPending' => Integer, + 'TopicArn' => String + } + }) + + tests("#get_topic_attributes('#{@topic_arn})").formats(get_topic_attributes_format) do + Fog::AWS[:sns].get_topic_attributes(@topic_arn).body + end + + tests("#delete_topic('#{@topic_arn}')").formats(Aws::SNS::Formats::BASIC) do + Fog::AWS[:sns].delete_topic(@topic_arn).body + end + + end + + tests('failure') do + + end + +end diff --git a/tests/requests/sqs/helper.rb b/tests/requests/sqs/helper.rb new file mode 100644 index 000000000..ff0a01473 --- /dev/null +++ b/tests/requests/sqs/helper.rb @@ -0,0 +1,9 @@ +class Aws + module SQS + module Formats + BASIC = { + 'ResponseMetadata' => {'RequestId' => String} + } + end + end +end diff --git a/tests/requests/sqs/message_tests.rb b/tests/requests/sqs/message_tests.rb new file mode 100644 index 000000000..e7502b34d --- /dev/null +++ b/tests/requests/sqs/message_tests.rb @@ -0,0 +1,51 @@ +Shindo.tests('Aws::SQS | message requests', ['aws']) do + + tests('success') do + + @queue_url = Fog::AWS[:sqs].create_queue('fog_message_tests').body['QueueUrl'] + + send_message_format = Aws::SQS::Formats::BASIC.merge({ + 'MessageId' => String, + 'MD5OfMessageBody' => String + }) + + tests("#send_message('#{@queue_url}', 'message')").formats(send_message_format) do + Fog::AWS[:sqs].send_message(@queue_url, 'message').body + end + + receive_message_format = Aws::SQS::Formats::BASIC.merge({ + 'Message' => [{ + 'Attributes' => { + 'ApproximateFirstReceiveTimestamp' => Time, + 'ApproximateReceiveCount' => Integer, + 'SenderId' => String, + 'SentTimestamp' => Time + }, + 'Body' => String, + 'MD5OfBody' => String, + 'MessageId' => String, + 'ReceiptHandle' => String + }] + }) + + tests("#receive_message").formats(receive_message_format) do + data = Fog::AWS[:sqs].receive_message(@queue_url).body + @receipt_handle = data['Message'].first['ReceiptHandle'] + data + end + + tests("#change_message_visibility('#{@queue_url}, '#{@receipt_handle}', 60)").formats(Aws::SQS::Formats::BASIC) do + Fog::AWS[:sqs].change_message_visibility(@queue_url, @receipt_handle, 60).body + end + + tests("#delete_message('#{@queue_url}', '#{@receipt_handle}')").formats(Aws::SQS::Formats::BASIC) do + Fog::AWS[:sqs].delete_message(@queue_url, @receipt_handle).body + end + + unless Fog.mocking? + Fog::AWS[:sqs].delete_queue(@queue_url) + end + + end + +end diff --git a/tests/requests/sqs/queue_tests.rb b/tests/requests/sqs/queue_tests.rb new file mode 100644 index 000000000..f0e278a98 --- /dev/null +++ b/tests/requests/sqs/queue_tests.rb @@ -0,0 +1,50 @@ +Shindo.tests('Aws::SQS | queue requests', ['aws']) do + + tests('success') do + + create_queue_format = Aws::SQS::Formats::BASIC.merge({ + 'QueueUrl' => String + }) + + tests("#create_queue('fog_queue_tests')").formats(create_queue_format) do + data = Fog::AWS[:sqs].create_queue('fog_queue_tests').body + @queue_url = data['QueueUrl'] + data + end + + list_queues_format = Aws::SQS::Formats::BASIC.merge({ + 'QueueUrls' => [String] + }) + + tests("#list_queues").formats(list_queues_format) do + Fog::AWS[:sqs].list_queues.body + end + + tests("#set_queue_attributes('#{@queue_url}', 'VisibilityTimeout', 60)").formats(Aws::SQS::Formats::BASIC) do + Fog::AWS[:sqs].set_queue_attributes(@queue_url, 'VisibilityTimeout', 60).body + end + + get_queue_attributes_format = Aws::SQS::Formats::BASIC.merge({ + 'Attributes' => { + 'ApproximateNumberOfMessages' => Integer, + 'ApproximateNumberOfMessagesNotVisible' => Integer, + 'CreatedTimestamp' => Time, + 'MaximumMessageSize' => Integer, + 'LastModifiedTimestamp' => Time, + 'MessageRetentionPeriod' => Integer, + 'QueueArn' => String, + 'VisibilityTimeout' => Integer + } + }) + + tests("#get_queue_attributes('#{@queue_url}', 'All')").formats(get_queue_attributes_format) do + Fog::AWS[:sqs].get_queue_attributes(@queue_url, 'All').body + end + + tests("#delete_queue('#{@queue_url}')").formats(Aws::SQS::Formats::BASIC) do + Fog::AWS[:sqs].delete_queue(@queue_url).body + end + + end + +end diff --git a/tests/requests/storage/acl_utils_tests.rb b/tests/requests/storage/acl_utils_tests.rb new file mode 100644 index 000000000..5df8ce856 --- /dev/null +++ b/tests/requests/storage/acl_utils_tests.rb @@ -0,0 +1,209 @@ +require 'fog/aws/requests/storage/acl_utils' + +Shindo.tests('Fog::Storage::AWS | ACL utils', ["aws"]) do + tests(".hash_to_acl") do + tests(".hash_to_acl({}) at xpath //AccessControlPolicy").returns("", "has an empty AccessControlPolicy") do + xml = Fog::Storage::AWS.hash_to_acl({}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy").first.content.chomp + end + + tests(".hash_to_acl({}) at xpath //AccessControlPolicy/Owner").returns(nil, "does not have an Owner element") do + xml = Fog::Storage::AWS.hash_to_acl({}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/Owner").first + end + + tests(".hash_to_acl('Owner' => {}) at xpath //AccessControlPolicy/Owner").returns(nil, "does not have an Owner element") do + xml = Fog::Storage::AWS.hash_to_acl('Owner' => {}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/Owner").first + end + + tests(".hash_to_acl('Owner' => {'ID' => 'abcdef0123456789'}) at xpath //AccessControlPolicy/Owner/ID").returns("abcdef0123456789", "returns the Owner ID") do + xml = Fog::Storage::AWS.hash_to_acl('Owner' => {'ID' => 'abcdef0123456789'}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/Owner/ID").first.content + end + + tests(".hash_to_acl('Owner' => {'DisplayName' => 'bob'}) at xpath //AccessControlPolicy/Owner/ID").returns(nil, "does not have an Owner ID element") do + xml = Fog::Storage::AWS.hash_to_acl('Owner' => {'DisplayName' => 'bob'}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/Owner/ID").first + end + + tests(".hash_to_acl('Owner' => {'DisplayName' => 'bob'}) at xpath //AccessControlPolicy/Owner/DisplayName").returns("bob", "returns the Owner DisplayName") do + xml = Fog::Storage::AWS.hash_to_acl('Owner' => {'DisplayName' => 'bob'}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/Owner/DisplayName").first.content + end + + tests(".hash_to_acl('Owner' => {'ID' => 'abcdef0123456789'}) at xpath //AccessControlPolicy/Owner/DisplayName").returns(nil, "does not have an Owner DisplayName element") do + xml = Fog::Storage::AWS.hash_to_acl('Owner' => {'ID' => 'abcdef0123456789'}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/Owner/DisplayName").first + end + + tests(".hash_to_acl({}) at xpath //AccessControlPolicy/AccessControlList").returns(nil, "has no AccessControlList") do + xml = Fog::Storage::AWS.hash_to_acl({}) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlPolicy").first + end + + acl = { + 'AccessControlList' => [ + { + 'Grantee' => { + 'ID' => 'abcdef0123456789', + 'DisplayName' => 'bob' + }, + 'Permission' => 'READ' + } + ] + } + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee").returns("CanonicalUser", "has an xsi:type of CanonicalUser") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee").first.attributes["type"].value + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/ID").returns("abcdef0123456789", "returns the Grantee ID") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/ID").first.content + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/DisplayName").returns("bob", "returns the Grantee DisplayName") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/DisplayName").first.content + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Permission").returns("READ", "returns the Grantee Permission") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Permission").first.content + end + + acl = { + 'AccessControlList' => [ + { + 'Grantee' => { + 'EmailAddress' => 'user@example.com' + }, + 'Permission' => 'FULL_CONTROL' + } + ] + } + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee").returns("AmazonCustomerByEmail", "has an xsi:type of AmazonCustomerByEmail") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee").first.attributes["type"].value + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/EmailAddress").returns("user@example.com", "returns the Grantee EmailAddress") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/EmailAddress").first.content + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Permission").returns("FULL_CONTROL", "returns the Grantee Permission") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Permission").first.content + end + + acl = { + 'AccessControlList' => [ + { + 'Grantee' => { + 'URI' => 'http://acs.amazonaws.com/groups/global/AllUsers' + }, + 'Permission' => 'WRITE' + } + ] + } + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee").returns("Group", "has an xsi:type of Group") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee").first.attributes["type"].value + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/URI").returns("http://acs.amazonaws.com/groups/global/AllUsers", "returns the Grantee URI") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/URI").first.content + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Permission").returns("WRITE", "returns the Grantee Permission") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Permission").first.content + end + + acl = { + 'AccessControlList' => [ + { + 'Grantee' => { + 'ID' => 'abcdef0123456789', + 'DisplayName' => 'bob' + }, + 'Permission' => 'READ' + }, + { + 'Grantee' => { + 'EmailAddress' => 'user@example.com' + }, + 'Permission' => 'FULL_CONTROL' + }, + { + 'Grantee' => { + 'URI' => 'http://acs.amazonaws.com/groups/global/AllUsers' + }, + 'Permission' => 'WRITE' + } + ] + } + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant").returns(3, "has three elements") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant").size + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/ID").returns("abcdef0123456789", "returns the first Grant's Grantee ID") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/ID").first.content + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/EmailAddress").returns("user@example.com", "returns the second Grant's Grantee EmailAddress") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/EmailAddress").first.content + end + + tests(".hash_to_acl(#{acl.inspect}) at xpath //AccessControlPolicy/AccessControlList/Grant/Grantee/URI").returns("http://acs.amazonaws.com/groups/global/AllUsers", "returns the third Grant's Grantee URI") do + xml = Fog::Storage::AWS.hash_to_acl(acl) + Nokogiri::XML(xml).xpath("//AccessControlPolicy/AccessControlList/Grant/Grantee/URI").first.content + end + end + + tests(".acl_to_hash") do + acl_xml = <<-XML + + + 2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0 + me + + + + + 2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0 + me + + FULL_CONTROL + + + +XML + + tests(".acl_to_hash(#{acl_xml.inspect})").returns({ + "Owner" => { + "DisplayName" => "me", + "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0" + }, + "AccessControlList" => [{ + "Grantee" => { + "DisplayName" => "me", + "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0" + }, + "Permission" => "FULL_CONTROL" + }] + }, 'returns hash of ACL XML') do + Fog::Storage::AWS.acl_to_hash(acl_xml) + end + end +end diff --git a/tests/requests/storage/bucket_tests.rb b/tests/requests/storage/bucket_tests.rb new file mode 100644 index 000000000..c182cc1d4 --- /dev/null +++ b/tests/requests/storage/bucket_tests.rb @@ -0,0 +1,379 @@ +Shindo.tests('Fog::Storage[:aws] | bucket requests', ["aws"]) do + @aws_bucket_name = 'fogbuckettests-' + Time.now.to_i.to_s(32) + + tests('success') do + + @bucket_format = { + 'CommonPrefixes' => [], + 'IsTruncated' => Fog::Boolean, + 'Marker' => NilClass, + 'MaxKeys' => Integer, + 'Name' => String, + 'Prefix' => NilClass, + 'Contents' => [{ + 'ETag' => String, + 'Key' => String, + 'LastModified' => Time, + 'Owner' => { + 'DisplayName' => String, + 'ID' => String + }, + 'Size' => Integer, + 'StorageClass' => String + }] + } + @bucket_lifecycle_format = { + 'Rules' => [{ + 'ID' => String, + 'Prefix' => Fog::Nullable::String, + 'Enabled' => Fog::Boolean, + 'Expiration' => Fog::Nullable::Hash, + 'Transition' => Fog::Nullable::Hash + }] + } + + @service_format = { + 'Buckets' => [{ + 'CreationDate' => Time, + 'Name' => String, + }], + 'Owner' => { + 'DisplayName' => String, + 'ID' => String + } + } + + tests("#put_bucket('#{@aws_bucket_name}')").succeeds do + Fog::Storage[:aws].put_bucket(@aws_bucket_name) + @aws_owner = Fog::Storage[:aws].get_bucket_acl(Fog::Storage[:aws].directories.first.key).body['Owner'] + end + + tests('put existing bucket - default region') do + Fog::Storage[:aws].put_bucket(@aws_bucket_name) + + tests("#put_bucket('#{@aws_bucket_name}') existing").succeeds do + Fog::Storage[:aws].put_bucket(@aws_bucket_name) + end + end + + tests("#get_service").formats(@service_format) do + Fog::Storage[:aws].get_service.body + end + + file = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'y', :key => 'x') + + tests("#get_bucket('#{@aws_bucket_name}')").formats(@bucket_format) do + Fog::Storage[:aws].get_bucket(@aws_bucket_name).body + end + + tests("#head_bucket('#{@aws_bucket_name}')").succeeds do + Fog::Storage[:aws].head_bucket(@aws_bucket_name) + end + + file.destroy + + file1 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'a', :key => 'a/a1/file1') + file2 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'ab', :key => 'a/file2') + file3 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'abc', :key => 'b/file3') + file4 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'abcd', :key => 'file4') + + tests("#get_bucket('#{@aws_bucket_name}')") do + before do + @bucket = Fog::Storage[:aws].get_bucket(@aws_bucket_name) + end + + tests(".body['Contents'].map{|n| n['Key']}").returns(["a/a1/file1", "a/file2", "b/file3", "file4"]) do + @bucket.body['Contents'].map{|n| n['Key']} + end + + tests(".body['Contents'].map{|n| n['Size']}").returns([1, 2, 3, 4]) do + @bucket.body['Contents'].map{|n| n['Size']} + end + + tests(".body['CommonPrefixes']").returns([]) do + @bucket.body['CommonPrefixes'] + end + end + + tests("#get_bucket('#{@aws_bucket_name}', 'delimiter' => '/')") do + before do + @bucket = Fog::Storage[:aws].get_bucket(@aws_bucket_name, 'delimiter' => '/') + end + + tests(".body['Contents'].map{|n| n['Key']}").returns(['file4']) do + @bucket.body['Contents'].map{|n| n['Key']} + end + + tests(".body['CommonPrefixes']").returns(['a/', 'b/']) do + @bucket.body['CommonPrefixes'] + end + end + + tests("#get_bucket('#{@aws_bucket_name}', 'delimiter' => '/', 'prefix' => 'a/')") do + before do + @bucket = Fog::Storage[:aws].get_bucket(@aws_bucket_name, 'delimiter' => '/', 'prefix' => 'a/') + end + + tests(".body['Contents'].map{|n| n['Key']}").returns(['a/file2']) do + @bucket.body['Contents'].map{|n| n['Key']} + end + + tests(".body['CommonPrefixes']").returns(['a/a1/']) do + @bucket.body['CommonPrefixes'] + end + end + + file1.destroy; file2.destroy; file3.destroy; file4.destroy + + tests("#get_bucket_location('#{@aws_bucket_name}')").formats('LocationConstraint' => NilClass) do + Fog::Storage[:aws].get_bucket_location(@aws_bucket_name).body + end + + tests("#get_request_payment('#{@aws_bucket_name}')").formats('Payer' => String) do + Fog::Storage[:aws].get_request_payment(@aws_bucket_name).body + end + + tests("#put_request_payment('#{@aws_bucket_name}', 'Requester')").succeeds do + Fog::Storage[:aws].put_request_payment(@aws_bucket_name, 'Requester') + end + + # This should show a warning, but work (second parameter is options hash for now) + tests("#put_bucket_website('#{@aws_bucket_name}', 'index.html')").succeeds do + Fog::Storage[:aws].put_bucket_website(@aws_bucket_name, 'index.html') + end + + tests("#put_bucket_website('#{@aws_bucket_name}', :IndexDocument => 'index.html')").succeeds do + Fog::Storage[:aws].put_bucket_website(@aws_bucket_name, :IndexDocument => 'index.html') + end + + tests("#put_bucket_website('#{@aws_bucket_name}', :RedirectAllRequestsTo => 'redirect.example..com')").succeeds do + Fog::Storage[:aws].put_bucket_website(@aws_bucket_name, :RedirectAllRequestsTo => 'redirect.example.com') + end + + tests("#put_bucket_acl('#{@aws_bucket_name}', 'private')").succeeds do + Fog::Storage[:aws].put_bucket_acl(@aws_bucket_name, 'private') + end + + acl = { + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => @aws_owner, + 'Permission' => "FULL_CONTROL" + } + ] + } + tests("#put_bucket_acl('#{@aws_bucket_name}', hash with id)").returns(acl) do + Fog::Storage[:aws].put_bucket_acl(@aws_bucket_name, acl) + Fog::Storage[:aws].get_bucket_acl(@aws_bucket_name).body + end + + tests("#put_bucket_acl('#{@aws_bucket_name}', hash with email)").returns({ + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => { 'ID' => 'f62f0218873cfa5d56ae9429ae75a592fec4fd22a5f24a20b1038a7db9a8f150', 'DisplayName' => 'mtd' }, + 'Permission' => "FULL_CONTROL" + } + ] + }) do + pending if Fog.mocking? + Fog::Storage[:aws].put_bucket_acl(@aws_bucket_name, { + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => { 'EmailAddress' => 'mtd@amazon.com' }, + 'Permission' => "FULL_CONTROL" + } + ] + }) + Fog::Storage[:aws].get_bucket_acl(@aws_bucket_name).body + end + + acl = { + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => { 'URI' => 'http://acs.amazonaws.com/groups/global/AllUsers' }, + 'Permission' => "FULL_CONTROL" + } + ] + } + tests("#put_bucket_acl('#{@aws_bucket_name}', hash with uri)").returns(acl) do + Fog::Storage[:aws].put_bucket_acl(@aws_bucket_name, acl) + Fog::Storage[:aws].get_bucket_acl(@aws_bucket_name).body + end + + tests("#delete_bucket_website('#{@aws_bucket_name}')").succeeds do + pending if Fog.mocking? + Fog::Storage[:aws].delete_bucket_website(@aws_bucket_name) + end + + tests('bucket lifecycle') do + pending if Fog.mocking? + + lifecycle = {'Rules' => [{'ID' => 'test rule', 'Prefix' => '/prefix', 'Enabled' => true, 'Days' => 42}]} + tests('non-existant bucket') do + tests('#put_bucket_lifecycle').returns([404, 'NoSuchBucket']) do + begin + Fog::Storage[:aws].put_bucket_lifecycle('fognonbucket', lifecycle) + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + tests('#get_bucket_lifecycle').returns([404, 'NoSuchBucket']) do + begin + Fog::Storage[:aws].get_bucket_lifecycle('fognonbucket') + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + tests('#delete_bucket_lifecycle').returns([404, 'NoSuchBucket']) do + begin + Fog::Storage[:aws].delete_bucket_lifecycle('fognonbucket') + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + end + tests('no lifecycle') do + tests('#get_bucket_lifecycle').returns([404, 'NoSuchLifecycleConfiguration']) do + begin + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name) + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + tests('#delete_bucket_lifecycle').succeeds do + Fog::Storage[:aws].delete_bucket_lifecycle(@aws_bucket_name) + end + end + tests('create').succeeds do + Fog::Storage[:aws].put_bucket_lifecycle(@aws_bucket_name, lifecycle) + end + tests('read').formats(@bucket_lifecycle_format) do + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name).body + end + lifecycle = { 'Rules' => 5.upto(6).map { |i| {'ID' => "rule\##{i}", 'Prefix' => i.to_s, 'Enabled' => true, 'Days' => i} } } + lifecycle_return = { 'Rules' => 5.upto(6).map { |i| {'ID' => "rule\##{i}", 'Prefix' => i.to_s, 'Enabled' => true, 'Expiration' => {'Days' => i}} } } + tests('update').returns(lifecycle_return) do + Fog::Storage[:aws].put_bucket_lifecycle(@aws_bucket_name, lifecycle) + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name).body + end + lifecycle = {'Rules' => [{'ID' => 'test rule', 'Prefix' => '/prefix', 'Enabled' => true, 'Expiration' => {'Days' => 42}, 'Transition' => {'Days' => 6, 'StorageClass'=>'GLACIER'}}]} + tests('transition').returns(lifecycle) do + Fog::Storage[:aws].put_bucket_lifecycle(@aws_bucket_name, lifecycle) + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name).body + end + lifecycle = {'Rules' => [{'ID' => 'test rule', 'Prefix' => '/prefix', 'Enabled' => true, 'Expiration' => {'Date' => '2012-12-31T00:00:00.000Z'}}]} + tests('date').returns(lifecycle) do + Fog::Storage[:aws].put_bucket_lifecycle(@aws_bucket_name, lifecycle) + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name).body + end + tests('delete').succeeds do + Fog::Storage[:aws].delete_bucket_lifecycle(@aws_bucket_name) + end + tests('read').returns([404, 'NoSuchLifecycleConfiguration']) do + begin + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name) + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + end + + tests("put_bucket_cors('#{@aws_bucket_name}', cors)").succeeds do + cors = {'CORSConfiguration' => + [ + { + 'AllowedOrigin' => 'http://localhost:3000', + 'AllowedMethod' => ['POST', 'GET'], + 'AllowedHeader' => '*', + 'MaxAgeSeconds' => 3000 + } + ] + } + Fog::Storage[:aws].put_bucket_cors(@aws_bucket_name, cors) + end + + tests("bucket tagging") do + + tests("#put_bucket_tagging('#{@aws_bucket_name}')").succeeds do + Fog::Storage[:aws].put_bucket_tagging(@aws_bucket_name, {'Key1' => 'Value1', 'Key2' => 'Value2'}) + end + + tests("#get_bucket_tagging('#{@aws_bucket_name}')"). + returns('BucketTagging' => {'Key1' => 'Value1', 'Key2' => 'Value2'}) do + Fog::Storage[:aws].get_bucket_tagging(@aws_bucket_name).body + end + + tests("#delete_bucket_tagging('#{@aws_bucket_name}')").succeeds do + Fog::Storage[:aws].delete_bucket_tagging(@aws_bucket_name) + end + end + + tests("#delete_bucket('#{@aws_bucket_name}')").succeeds do + Fog::Storage[:aws].delete_bucket(@aws_bucket_name) + end + + end + + tests('failure') do + + tests("#delete_bucket('fognonbucket')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].delete_bucket('fognonbucket') + end + + @bucket = Fog::Storage[:aws].directories.create(:key => 'fognonempty') + @file = @bucket.files.create(:key => 'foo', :body => 'bar') + + tests("#delete_bucket('fognonempty')").raises(Excon::Errors::Conflict) do + Fog::Storage[:aws].delete_bucket('fognonempty') + end + + @file.destroy + @bucket.destroy + + tests("#get_bucket('fognonbucket')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_bucket('fognonbucket') + end + + tests("#get_bucket_location('fognonbucket')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_bucket_location('fognonbucket') + end + + tests("#get_request_payment('fognonbucket')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_request_payment('fognonbucket') + end + + tests("#put_request_payment('fognonbucket', 'Requester')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].put_request_payment('fognonbucket', 'Requester') + end + + tests("#put_bucket_acl('fognonbucket', 'invalid')").raises(Excon::Errors::BadRequest) do + Fog::Storage[:aws].put_bucket_acl('fognonbucket', 'invalid') + end + + tests("#put_bucket_website('fognonbucket', 'index.html')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].put_bucket_website('fognonbucket', 'index.html') + end + + tests('put existing bucket - non-default region') do + storage_eu_endpoint = Fog::Storage[:aws] + storage_eu_endpoint.region = "eu-west-1" + storage_eu_endpoint.put_bucket(@aws_bucket_name) + + tests("#put_bucket('#{@aws_bucket_name}') existing").raises(Excon::Errors::Conflict) do + storage_eu_endpoint.put_bucket(@aws_bucket_name) + end + end + + tests("#put_bucket_website('fognonbucket', :RedirectAllRequestsTo => 'redirect.example.com')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].put_bucket_website('fognonbucket', :RedirectAllRequestsTo => 'redirect.example.com') + end + + end + + # don't keep the bucket around + Fog::Storage[:aws].delete_bucket(@aws_bucket_name) rescue nil +end diff --git a/tests/requests/storage/cors_utils_tests.rb b/tests/requests/storage/cors_utils_tests.rb new file mode 100644 index 000000000..c8c8847c2 --- /dev/null +++ b/tests/requests/storage/cors_utils_tests.rb @@ -0,0 +1,108 @@ +require 'fog/aws/requests/storage/cors_utils' + +Shindo.tests('Fog::Storage::AWS | CORS utils', ["aws"]) do + tests(".hash_to_cors") do + tests(".hash_to_cors({}) at xpath //CORSConfiguration").returns("", "has an empty CORSConfiguration") do + xml = Fog::Storage::AWS.hash_to_cors({}) + Nokogiri::XML(xml).xpath("//CORSConfiguration").first.content.chomp + end + + tests(".hash_to_cors({}) at xpath //CORSConfiguration/CORSRule").returns(nil, "has no CORSRules") do + xml = Fog::Storage::AWS.hash_to_cors({}) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule").first + end + + cors = { + 'CORSConfiguration' => [ + { + 'AllowedOrigin' => ['origin_123', 'origin_456'], + 'AllowedMethod' => ['GET', 'POST'], + 'AllowedHeader' => ['Accept', 'Content-Type'], + 'ID' => 'blah-888', + 'MaxAgeSeconds' => 2500, + 'ExposeHeader' => ['x-some-header', 'x-other-header'] + } + ] + } + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedOrigin").returns("origin_123", "returns the CORSRule AllowedOrigin") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedOrigin")[0].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedOrigin").returns("origin_456", "returns the CORSRule AllowedOrigin") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedOrigin")[1].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedMethod").returns("GET", "returns the CORSRule AllowedMethod") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedMethod")[0].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedMethod").returns("POST", "returns the CORSRule AllowedMethod") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedMethod")[1].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedHeader").returns("Accept", "returns the CORSRule AllowedHeader") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedHeader")[0].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedHeader").returns("Content-Type", "returns the CORSRule AllowedHeader") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedHeader")[1].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/ID").returns("blah-888", "returns the CORSRule ID") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/ID")[0].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/MaxAgeSeconds").returns("2500", "returns the CORSRule MaxAgeSeconds") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/MaxAgeSeconds")[0].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/ExposeHeader").returns("x-some-header", "returns the CORSRule ExposeHeader") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/ExposeHeader")[0].content + end + + tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/ExposeHeader").returns("x-other-header", "returns the CORSRule ExposeHeader") do + xml = Fog::Storage::AWS.hash_to_cors(cors) + Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/ExposeHeader")[1].content + end + end + + tests(".cors_to_hash") do + cors_xml = <<-XML + + + http://www.example.com + http://www.example2.com + Content-Length + X-Foobar + PUT + GET + 3000 + x-amz-server-side-encryption + x-amz-balls + + +XML + + tests(".cors_to_hash(#{cors_xml.inspect})").returns({ + "CORSConfiguration" => [{ + "AllowedOrigin" => ["http://www.example.com", "http://www.example2.com"], + "AllowedHeader" => ["Content-Length", "X-Foobar"], + "AllowedMethod" => ["PUT", "GET"], + "MaxAgeSeconds" => 3000, + "ExposeHeader" => ["x-amz-server-side-encryption", "x-amz-balls"] + }] + }, 'returns hash of CORS XML') do + Fog::Storage::AWS.cors_to_hash(cors_xml) + end + end +end diff --git a/tests/requests/storage/delete_multiple_objects_tests.rb b/tests/requests/storage/delete_multiple_objects_tests.rb new file mode 100644 index 000000000..9da91d43c --- /dev/null +++ b/tests/requests/storage/delete_multiple_objects_tests.rb @@ -0,0 +1,12 @@ +Shindo.tests('Aws::Storage | delete_multiple_objects', ['aws']) do + @directory = Fog::Storage[:aws].directories.create(:key => 'fogobjecttests-' + Time.now.to_i.to_s(32)) + + tests("doesn't alter options") do + version_id = {'fog_object' => ['12345']} + options = {:quiet => true, 'versionId' => version_id} + Fog::Storage[:aws].delete_multiple_objects(@directory.identity, ['fog_object'], options) + + test(":quiet is unchanged") { options[:quiet] } + test("'versionId' is unchanged") { options['versionId'] == version_id } + end +end diff --git a/tests/requests/storage/multipart_upload_tests.rb b/tests/requests/storage/multipart_upload_tests.rb new file mode 100644 index 000000000..7aad4464a --- /dev/null +++ b/tests/requests/storage/multipart_upload_tests.rb @@ -0,0 +1,121 @@ +Shindo.tests('Fog::Storage[:aws] | multipart upload requests', ["aws"]) do + + @directory = Fog::Storage[:aws].directories.create(:key => uniq_id('fogmultipartuploadtests')) + + tests('success') do + + @initiate_multipart_upload_format = { + 'Bucket' => String, + 'Key' => String, + 'UploadId' => String + } + + tests("#initiate_multipart_upload('#{@directory.identity}')", 'fog_multipart_upload').formats(@initiate_multipart_upload_format) do + data = Fog::Storage[:aws].initiate_multipart_upload(@directory.identity, 'fog_multipart_upload').body + @upload_id = data['UploadId'] + data + end + + @list_multipart_uploads_format = { + 'Bucket' => String, + 'IsTruncated' => Fog::Boolean, + 'MaxUploads' => Integer, + 'KeyMarker' => NilClass, + 'NextKeyMarker' => String, + 'NextUploadIdMarker' => Fog::Nullable::String, + 'Upload' => [{ + 'Initiated' => Time, + 'Initiator' => { + 'DisplayName' => String, + 'ID' => String + }, + 'Key' => String, + 'Owner' => { + 'DisplayName' => String, + 'ID' => String + }, + 'StorageClass' => String, + 'UploadId' => String + }], + 'UploadIdMarker' => NilClass, + } + + tests("#list_multipart_uploads('#{@directory.identity})").formats(@list_multipart_uploads_format) do + pending if Fog.mocking? + Fog::Storage[:aws].list_multipart_uploads(@directory.identity).body + end + + @parts = [] + + tests("#upload_part('#{@directory.identity}', 'fog_multipart_upload', '#{@upload_id}', 1, ('x' * 6 * 1024 * 1024))").succeeds do + data = Fog::Storage[:aws].upload_part(@directory.identity, 'fog_multipart_upload', @upload_id, 1, ('x' * 6 * 1024 * 1024)) + @parts << data.headers['ETag'] + end + + @list_parts_format = { + 'Bucket' => String, + 'Initiator' => { + 'DisplayName' => String, + 'ID' => String + }, + 'IsTruncated' => Fog::Boolean, + 'Key' => String, + 'MaxParts' => Integer, + 'NextPartNumberMarker' => String, + 'Part' => [{ + 'ETag' => String, + 'LastModified' => Time, + 'PartNumber' => Integer, + 'Size' => Integer + }], + 'PartNumberMarker' => String, + 'StorageClass' => String, + 'UploadId' => String + } + + tests("#list_parts('#{@directory.identity}', 'fog_multipart_upload', '#{@upload_id}')").formats(@list_parts_format) do + pending if Fog.mocking? + Fog::Storage[:aws].list_parts(@directory.identity, 'fog_multipart_upload', @upload_id).body + end + + @parts << Fog::Storage[:aws].upload_part(@directory.identity, 'fog_multipart_upload', @upload_id, 2, ('x' * 4 * 1024 * 1024)).headers['ETag'] + + @complete_multipart_upload_format = { + 'Bucket' => String, + 'ETag' => String, + 'Key' => String, + 'Location' => String + } + + tests("#complete_multipart_upload('#{@directory.identity}', 'fog_multipart_upload', '#{@upload_id}', #{@parts.inspect})").formats(@complete_multipart_upload_format) do + Fog::Storage[:aws].complete_multipart_upload(@directory.identity, 'fog_multipart_upload', @upload_id, @parts).body + end + + tests("#get_object('#{@directory.identity}', 'fog_multipart_upload').body").succeeds do + Fog::Storage[:aws].get_object(@directory.identity, 'fog_multipart_upload').body == ('x' * 10 * 1024 * 1024) + end + + @directory.files.new(:key => 'fog_multipart_upload').destroy + + @upload_id = Fog::Storage[:aws].initiate_multipart_upload(@directory.identity, 'fog_multipart_abort').body['UploadId'] + + tests("#abort_multipart_upload('#{@directory.identity}', 'fog_multipart_abort', '#{@upload_id}')").succeeds do + Fog::Storage[:aws].abort_multipart_upload(@directory.identity, 'fog_multipart_abort', @upload_id) + end + + end + + tests('failure') do + + tests("initiate_multipart_upload") + tests("list_multipart_uploads") + tests("upload_part") + tests("list_parts") + tests("complete_multipart_upload") + tests("abort_multipart_upload") + + end + + @directory.destroy + +end diff --git a/tests/requests/storage/object_tests.rb b/tests/requests/storage/object_tests.rb new file mode 100644 index 000000000..420e2d58e --- /dev/null +++ b/tests/requests/storage/object_tests.rb @@ -0,0 +1,189 @@ +# encoding: utf-8 + +Shindo.tests('Aws::Storage | object requests', ['aws']) do + @directory = Fog::Storage[:aws].directories.create(:key => 'fogobjecttests-' + Time.now.to_i.to_s(32)) + @aws_owner = Fog::Storage[:aws].get_bucket_acl(@directory.key).body['Owner'] + + tests('success') do + + @multiple_delete_format = { + 'DeleteResult' => [{ + 'Deleted' => { + 'Key' => String + } + }] + } + + tests("#put_object('#{@directory.identity}', 'fog_object', lorem_file)").succeeds do + Fog::Storage[:aws].put_object(@directory.identity, 'fog_object', lorem_file) + end + + if RUBY_VERSION =~ /^1\.8\./ + tests("#put_object('#{@directory.identity}', 'fog_object', lorem_file, {'x-amz-meta-json' => 'ä'}").succeeds do + Fog::Storage[:aws].put_object(@directory.identity, 'fog_object', lorem_file, {'x-amz-meta-json' => 'ä'}) + end + end + + tests("#copy_object('#{@directory.identity}', 'fog_object', '#{@directory.identity}', 'fog_other_object')").succeeds do + Fog::Storage[:aws].copy_object(@directory.identity, 'fog_object', @directory.identity, 'fog_other_object') + end + + @directory.files.get('fog_other_object').destroy + + tests("#get_object('#{@directory.identity}', 'fog_object')").returns(lorem_file.read) do + Fog::Storage[:aws].get_object(@directory.identity, 'fog_object').body + end + + tests("#get_object('#{@directory.identity}', 'fog_object', &block)").returns(lorem_file.read) do + data = '' + Fog::Storage[:aws].get_object(@directory.identity, 'fog_object') do |chunk, remaining_bytes, total_bytes| + data << chunk + end + data + end + + tests("#get_object('#{@directory.identity}', 'fog_object', {'Range' => 'bytes=0-20'})").returns(lorem_file.read[0..20]) do + Fog::Storage[:aws].get_object(@directory.identity, 'fog_object', {'Range' => 'bytes=0-20'}).body + end + + tests("#get_object('#{@directory.identity}', 'fog_object', {'Range' => 'bytes=0-0'})").returns(lorem_file.read[0..0]) do + Fog::Storage[:aws].get_object(@directory.identity, 'fog_object', {'Range' => 'bytes=0-0'}).body + end + + tests("#head_object('#{@directory.identity}', 'fog_object')").succeeds do + Fog::Storage[:aws].head_object(@directory.identity, 'fog_object') + end + + tests("#post_object_restore('#{@directory.identity}', 'fog_object')").succeeds do + pending unless Fog.mocking? + Fog::Storage[:aws].post_object_restore(@directory.identity, 'fog_object') + end + + tests("#put_object_acl('#{@directory.identity}', 'fog_object', 'private')").succeeds do + Fog::Storage[:aws].put_object_acl(@directory.identity, 'fog_object', 'private') + end + + acl = { + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => @aws_owner, + 'Permission' => "FULL_CONTROL" + } + ]} + tests("#put_object_acl('#{@directory.identity}', 'fog_object', hash with id)").returns(acl) do + Fog::Storage[:aws].put_object_acl(@directory.identity, 'fog_object', acl) + Fog::Storage[:aws].get_object_acl(@directory.identity, 'fog_object').body + end + + tests("#put_object_acl('#{@directory.identity}', 'fog_object', hash with email)").returns({ + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => { 'ID' => 'f62f0218873cfa5d56ae9429ae75a592fec4fd22a5f24a20b1038a7db9a8f150', 'DisplayName' => 'mtd' }, + 'Permission' => "FULL_CONTROL" + } + ]}) do + pending if Fog.mocking? + Fog::Storage[:aws].put_object_acl(@directory.identity, 'fog_object', { + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => { 'EmailAddress' => 'mtd@amazon.com' }, + 'Permission' => "FULL_CONTROL" + } + ]}) + Fog::Storage[:aws].get_object_acl(@directory.identity, 'fog_object').body + end + + acl = { + 'Owner' => @aws_owner, + 'AccessControlList' => [ + { + 'Grantee' => { 'URI' => 'http://acs.amazonaws.com/groups/global/AllUsers' }, + 'Permission' => "FULL_CONTROL" + } + ]} + tests("#put_object_acl('#{@directory.identity}', 'fog_object', hash with uri)").returns(acl) do + Fog::Storage[:aws].put_object_acl(@directory.identity, 'fog_object', acl) + Fog::Storage[:aws].get_object_acl(@directory.identity, 'fog_object').body + end + + tests("#delete_object('#{@directory.identity}', 'fog_object')").succeeds do + Fog::Storage[:aws].delete_object(@directory.identity, 'fog_object') + end + + tests("#get_object_http_url('#{@directory.identity}', 'fog_object', expiration timestamp)").returns(true) do + object_url = Fog::Storage[:aws].get_object_http_url(@directory.identity, 'fog_object', (Time.now + 60)) + (object_url =~ /http:\/\/#{Regexp.quote(@directory.identity)}\.s3\.amazonaws\.com\/fog_object/) != nil + end + + tests("delete_multiple_objects('#{@directory.identity}', ['fog_object', 'fog_other_object'])").formats(@multiple_delete_format) do + Fog::Storage[:aws].delete_multiple_objects(@directory.identity, ['fog_object', 'fog_other_object']).body + end + + end + + fognonbucket = uniq_id('fognonbucket') + + tests('failure') do + + tests("#put_object('#{fognonbucket}', 'fog_non_object', lorem_file)").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].put_object(fognonbucket, 'fog_non_object', lorem_file) + end + + unless RUBY_VERSION =~ /^1\.8\./ + tests("#put_object('#{@directory.identity}', 'fog_object', lorem_file, {'x-amz-meta-json' => 'ä'}").raises(Excon::Errors::BadRequest) do + Fog::Storage[:aws].put_object(@directory.identity, 'fog_object', lorem_file, {'x-amz-meta-json' => 'ä'}) + end + end + + tests("#copy_object('#{fognonbucket}', 'fog_object', '#{@directory.identity}', 'fog_other_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].copy_object(fognonbucket, 'fog_object', @directory.identity, 'fog_other_object') + end + + tests("#copy_object('#{@directory.identity}', 'fog_non_object', '#{@directory.identity}', 'fog_other_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].copy_object(@directory.identity, 'fog_non_object', @directory.identity, 'fog_other_object') + end + + tests("#copy_object('#{@directory.identity}', 'fog_object', 'fognonbucket', 'fog_other_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].copy_object(@directory.identity, 'fog_object', fognonbucket, 'fog_other_object') + end + + tests("#get_object('#{fognonbucket}', 'fog_non_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_object(fognonbucket, 'fog_non_object') + end + + tests("#get_object('#{@directory.identity}', 'fog_non_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_object(@directory.identity, 'fog_non_object') + end + + tests("#head_object(fognonbucket, 'fog_non_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].head_object(fognonbucket, 'fog_non_object') + end + + tests("#head_object('#{@directory.identity}', 'fog_non_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].head_object(@directory.identity, 'fog_non_object') + end + + tests("#delete_object('#{fognonbucket}', 'fog_non_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].delete_object(fognonbucket, 'fog_non_object') + end + + tests("#delete_multiple_objects('#{fognonbucket}', ['fog_non_object'])").raises(Excon::Errors::NotFound) do + pending if Fog.mocking? + Fog::Storage[:aws].delete_multiple_objects(fognonbucket, ['fog_non_object']) + end + + tests("#put_object_acl('#{@directory.identity}', 'fog_object', 'invalid')").raises(Excon::Errors::BadRequest) do + Fog::Storage[:aws].put_object_acl('#{@directory.identity}', 'fog_object', 'invalid') + end + + tests("#post_object_restore('#{@directory.identity}', 'fog_non_object')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].post_object_restore(@directory.identity, 'fog_non_object') + end + end + + @directory.destroy + +end diff --git a/tests/requests/storage/versioning_tests.rb b/tests/requests/storage/versioning_tests.rb new file mode 100644 index 000000000..f6f455d09 --- /dev/null +++ b/tests/requests/storage/versioning_tests.rb @@ -0,0 +1,258 @@ +def clear_bucket + Fog::Storage[:aws].get_bucket_object_versions(@aws_bucket_name).body['Versions'].each do |version| + object = version[version.keys.first] + Fog::Storage[:aws].delete_object(@aws_bucket_name, object['Key'], 'versionId' => object['VersionId']) + end +end + +def create_versioned_bucket + @aws_bucket_name = 'fogbuckettests-' + Fog::Mock.random_hex(16) + Fog::Storage[:aws].put_bucket(@aws_bucket_name) + Fog::Storage[:aws].put_bucket_versioning(@aws_bucket_name, 'Enabled') +end + +def delete_bucket + Fog::Storage[:aws].get_bucket_object_versions(@aws_bucket_name).body['Versions'].each do |version| + object = version[version.keys.first] + Fog::Storage[:aws].delete_object(@aws_bucket_name, object['Key'], 'versionId' => object['VersionId']) + end + + Fog::Storage[:aws].delete_bucket(@aws_bucket_name) +end + +Shindo.tests('Fog::Storage[:aws] | versioning', ["aws"]) do + tests('success') do + tests("#put_bucket_versioning") do + @aws_bucket_name = 'fogbuckettests-' + Fog::Mock.random_hex(16) + Fog::Storage[:aws].put_bucket(@aws_bucket_name) + + tests("#put_bucket_versioning('#{@aws_bucket_name}', 'Enabled')").succeeds do + Fog::Storage[:aws].put_bucket_versioning(@aws_bucket_name, 'Enabled') + end + + tests("#put_bucket_versioning('#{@aws_bucket_name}', 'Suspended')").succeeds do + Fog::Storage[:aws].put_bucket_versioning(@aws_bucket_name, 'Suspended') + end + + delete_bucket + end + + tests("#get_bucket_versioning('#{@aws_bucket_name}')") do + @aws_bucket_name = 'fogbuckettests-' + Fog::Mock.random_hex(16) + Fog::Storage[:aws].put_bucket(@aws_bucket_name) + + tests("#get_bucket_versioning('#{@aws_bucket_name}') without versioning").returns({}) do + Fog::Storage[:aws].get_bucket_versioning(@aws_bucket_name).body['VersioningConfiguration'] + end + + tests("#get_bucket_versioning('#{@aws_bucket_name}') with versioning enabled").returns('Enabled') do + Fog::Storage[:aws].put_bucket_versioning(@aws_bucket_name, 'Enabled') + Fog::Storage[:aws].get_bucket_versioning(@aws_bucket_name).body['VersioningConfiguration']['Status'] + end + + tests("#get_bucket_versioning('#{@aws_bucket_name}') with versioning suspended").returns('Suspended') do + Fog::Storage[:aws].put_bucket_versioning(@aws_bucket_name, 'Suspended') + Fog::Storage[:aws].get_bucket_versioning(@aws_bucket_name).body['VersioningConfiguration']['Status'] + end + + delete_bucket + end + + tests("#get_bucket_object_versions('#{@aws_bucket_name}')") do + + create_versioned_bucket + + before do + @versions = Fog::Storage[:aws].get_bucket_object_versions(@aws_bucket_name) + end + + v1 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'a', :key => 'file') + v2 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'ab', :key => v1.key) + v3 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'abc', :key => v1.key) + v4 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'abcd', :key => v1.key) + + tests("versions").returns([v4.version, v3.version, v2.version, v1.version]) do + @versions.body['Versions'].map {|v| v['Version']['VersionId']} + end + + tests("version sizes").returns([4, 3, 2, 1]) do + @versions.body['Versions'].map {|v| v['Version']['Size']} + end + + tests("latest version").returns(v4.version) do + latest = @versions.body['Versions'].find {|v| v['Version']['IsLatest']} + latest['Version']['VersionId'] + end + end + + tests("get_object('#{@aws_bucket_name}', 'file')") do + clear_bucket + + v1 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'a', :key => 'file') + v2 = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'ab', :key => v1.key) + + tests("get_object('#{@aws_bucket_name}', '#{v2.key}') returns the latest version").returns(v2.version) do + res = Fog::Storage[:aws].get_object(@aws_bucket_name, v2.key) + res.headers['x-amz-version-id'] + end + + tests("get_object('#{@aws_bucket_name}', '#{v1.key}', 'versionId' => '#{v1.version}') returns the specified version").returns(v1.version) do + res = Fog::Storage[:aws].get_object(@aws_bucket_name, v1.key, 'versionId' => v1.version) + res.headers['x-amz-version-id'] + end + + v2.destroy + + tests("get_object('#{@aws_bucket_name}', '#{v2.key}') raises exception if delete marker is latest version").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_object(@aws_bucket_name, v2.key) + end + end + + tests("delete_object('#{@aws_bucket_name}', 'file')") do + clear_bucket + + file = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'a', :key => 'file') + + tests("deleting an object just stores a delete marker").returns(true) do + file.destroy + versions = Fog::Storage[:aws].get_bucket_object_versions(@aws_bucket_name) + versions.body['Versions'].first.key?('DeleteMarker') + end + + tests("there are two versions: the original and the delete marker").returns(2) do + versions = Fog::Storage[:aws].get_bucket_object_versions(@aws_bucket_name) + versions.body['Versions'].size + end + + tests("deleting the delete marker makes the object available again").returns(file.version) do + versions = Fog::Storage[:aws].get_bucket_object_versions(@aws_bucket_name) + delete_marker = versions.body['Versions'].find { |v| v.key?('DeleteMarker') } + Fog::Storage[:aws].delete_object(@aws_bucket_name, file.key, 'versionId' => delete_marker['DeleteMarker']['VersionId']) + + res = Fog::Storage[:aws].get_object(@aws_bucket_name, file.key) + res.headers['x-amz-version-id'] + end + end + + tests("deleting_multiple_objects('#{@aws_bucket_name}", 'file') do + clear_bucket + + bucket = Fog::Storage[:aws].directories.get(@aws_bucket_name) + + file_count = 5 + file_names = [] + files = {} + file_count.times do |id| + file_names << "file_#{id}" + files[file_names.last] = bucket.files.create(:body => 'a', + :key => file_names.last) + end + + tests("deleting an object just stores a delete marker").returns(true) do + Fog::Storage[:aws].delete_multiple_objects(@aws_bucket_name, + file_names) + versions = Fog::Storage[:aws].get_bucket_object_versions( + @aws_bucket_name) + all_versions = {} + versions.body['Versions'].each do |version| + object = version[version.keys.first] + next if file_names.index(object['Key']).nil? + if !all_versions.key?(object['Key']) + all_versions[object['Key']] = version.key?('DeleteMarker') + else + all_versions[object['Key']] |= version.key?('DeleteMarker') + end + end + all_true = true + all_versions.values.each do |marker| + all_true = false if !marker + end + all_true + end + + tests("there are two versions: the original and the delete marker"). + returns(file_count*2) do + versions = Fog::Storage[:aws].get_bucket_object_versions( + @aws_bucket_name) + versions.body['Versions'].size + end + + tests("deleting the delete marker makes the object available again"). + returns(true) do + versions = Fog::Storage[:aws].get_bucket_object_versions( + @aws_bucket_name) + delete_markers = [] + file_versions = {} + versions.body['Versions'].each do |version| + object = version[version.keys.first] + next if object['VersionId'] == files[object['Key']].version + file_versions[object['Key']] = object['VersionId'] + end + + Fog::Storage[:aws].delete_multiple_objects(@aws_bucket_name, + file_names, + 'versionId' => file_versions) + all_true = true + file_names.each do |file| + res = Fog::Storage[:aws].get_object(@aws_bucket_name, file) + all_true = false if res.headers['x-amz-version-id'] != + files[file].version + end + all_true + end + + end + + tests("get_bucket('#{@aws_bucket_name}'") do + clear_bucket + + file = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'a', :key => 'file') + + tests("includes a non-DeleteMarker object").returns(1) do + Fog::Storage[:aws].get_bucket(@aws_bucket_name).body['Contents'].size + end + + file.destroy + + tests("does not include a DeleteMarker object").returns(0) do + Fog::Storage[:aws].get_bucket(@aws_bucket_name).body['Contents'].size + end + end + + delete_bucket + end + + tests('failure') do + create_versioned_bucket + + tests("#put_bucket_versioning('#{@aws_bucket_name}', 'bad_value')").raises(Excon::Errors::BadRequest) do + Fog::Storage[:aws].put_bucket_versioning(@aws_bucket_name, 'bad_value') + end + + tests("#put_bucket_versioning('fognonbucket', 'Enabled')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].put_bucket_versioning('fognonbucket', 'Enabled') + end + + tests("#get_bucket_versioning('fognonbucket')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_bucket_versioning('fognonbucket') + end + + tests("#get_bucket_object_versions('fognonbucket')").raises(Excon::Errors::NotFound) do + Fog::Storage[:aws].get_bucket_object_versions('fognonbucket') + end + + file = Fog::Storage[:aws].directories.get(@aws_bucket_name).files.create(:body => 'y', :key => 'x') + + tests("#get_object('#{@aws_bucket_name}', '#{file.key}', 'versionId' => 'bad_version'").raises(Excon::Errors::BadRequest) do + Fog::Storage[:aws].get_object(@aws_bucket_name, file.key, 'versionId' => '-1') + end + + tests("#delete_object('#{@aws_bucket_name}', '#{file.key}', 'versionId' => 'bad_version'").raises(Excon::Errors::BadRequest) do + Fog::Storage[:aws].delete_object(@aws_bucket_name, file.key, 'versionId' => '-1') + end + + end + + # don't keep the bucket around + delete_bucket +end diff --git a/tests/requests/sts/assume_role_tests.rb b/tests/requests/sts/assume_role_tests.rb new file mode 100644 index 000000000..43df5c69e --- /dev/null +++ b/tests/requests/sts/assume_role_tests.rb @@ -0,0 +1,19 @@ +Shindo.tests('Aws::STS | assume role', ['aws']) do + + @policy = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]} + + @response_format = { + 'SessionToken' => String, + 'SecretAccessKey' => String, + 'Expiration' => String, + 'AccessKeyId' => String, + 'Arn' => String, + 'RequestId' => String + } + + tests("#assume_role('rolename', 'assumed_role_session', 'external_id', #{@policy.inspect}, 900)").formats(@response_format) do + pending if Fog.mocking? + Fog::AWS[:sts].assume_role("rolename","assumed_role_session","external_id", @policy, 900).body + end + +end diff --git a/tests/requests/sts/assume_role_with_saml_tests.rb b/tests/requests/sts/assume_role_with_saml_tests.rb new file mode 100644 index 000000000..1e4aa4f3b --- /dev/null +++ b/tests/requests/sts/assume_role_with_saml_tests.rb @@ -0,0 +1,18 @@ +Shindo.tests('Aws::STS | assume role with SAML', ['aws']) do + + @policy = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]} + + @response_format = { + 'SessionToken' => String, + 'SecretAccessKey' => String, + 'Expiration' => String, + 'AccessKeyId' => String, + 'Arn' => String, + 'RequestId' => String + } + + tests("#assume_role_with_saml('role_arn', 'principal_arn', 'saml_assertion', #{@policy.inspect}, 900)").formats(@response_format) do + pending if Fog.mocking? + Fog::AWS[:sts].assume_role_with_saml("role_arn","principal_arn","saml_assertion", @policy, 900).body + end +end diff --git a/tests/requests/sts/get_federation_token_tests.rb b/tests/requests/sts/get_federation_token_tests.rb new file mode 100644 index 000000000..79bba8411 --- /dev/null +++ b/tests/requests/sts/get_federation_token_tests.rb @@ -0,0 +1,20 @@ +Shindo.tests('Aws::STS | session tokens', ['aws']) do + + @policy = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]} + + @federation_format = { + 'SessionToken' => String, + 'SecretAccessKey' => String, + 'Expiration' => String, + 'AccessKeyId' => String, + 'Arn' => String, + 'FederatedUserId' => String, + 'PackedPolicySize' => String, + 'RequestId' => String + } + + tests("#get_federation_token('test@fog.io', #{@policy.inspect})").formats(@federation_format) do + Fog::AWS[:sts].get_federation_token("test@fog.io", @policy).body + end + +end diff --git a/tests/requests/sts/session_token_tests.rb b/tests/requests/sts/session_token_tests.rb new file mode 100644 index 000000000..c4573cff6 --- /dev/null +++ b/tests/requests/sts/session_token_tests.rb @@ -0,0 +1,16 @@ +Shindo.tests('Aws::STS | session tokens', ['aws']) do + + @session_format = { + 'SessionToken' => String, + 'SecretAccessKey' => String, + 'Expiration' => String, + 'AccessKeyId' => String, + 'RequestId' => String + } + + tests("#get_session_token").formats(@session_format) do + pending if Fog.mocking? + Fog::AWS[:sts].get_session_token.body + end + +end diff --git a/tests/signaturev4_tests.rb b/tests/signaturev4_tests.rb new file mode 100644 index 000000000..82812dfdb --- /dev/null +++ b/tests/signaturev4_tests.rb @@ -0,0 +1,88 @@ +# encoding: utf-8 + +Shindo.tests('Aws | signaturev4', ['aws']) do + + @now = Fog::Time.utc(2011,9,9,23,36,0) + + # These testcases are from http://docs.amazonwebservices.com/general/latest/gr/signature-v4-test-suite.html + @signer = Fog::AWS::SignatureV4.new('AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY', 'us-east-1','host') + + tests('get-vanilla') do + returns(@signer.sign({:headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470' + end + end + + tests('get-vanilla-query-order-key with symbol keys') do + returns(@signer.sign({:query => {:'a' => 'foo', :'b' => 'foo'}, :headers => {:'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b' + end + end + + tests('get-vanilla-query-order-key') do + returns(@signer.sign({:query => {'a' => 'foo', 'b' => 'foo'}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b' + end + end + + tests('get-unreserved') do + returns(@signer.sign({:headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e' + end + end + + tests('post-x-www-form-urlencoded-parameter') do + returns(@signer.sign({:headers => {'Content-type' => 'application/x-www-form-urlencoded; charset=utf8', 'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :post, :path => '/', + :body => 'foo=bar'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71' + end + end + + tests('get with relative path') do + returns(@signer.sign({:query => {}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/foo/bar/../..'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470' + end + end + + tests('get with pointless .') do + returns(@signer.sign({:query => {}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/./foo'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a' + end + end + + tests('get with repeated / ') do + returns(@signer.sign({:query => {}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '//'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470' + end + end + + tests('get with repeated trailing / ') do + returns(@signer.sign({:query => {}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '//foo//'}, @now)) do + 'Aws4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19' + end + end + + tests('get signature as components') do + returns(@signer.signature_parameters({:query => {'a' => 'foo', 'b' => 'foo'}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, @now)) do + { + 'X-Amz-Algorithm' => 'Aws4-HMAC-SHA256', + 'X-Amz-Credential' => 'AKIDEXAMPLE/20110909/us-east-1/host/aws4_request', + 'X-Amz-SignedHeaders' => 'date;host', + 'X-Amz-Signature' => 'a6c6304682c74bcaebeeab2fdfb8041bbb39c6976300791a283057bccf333fb2' + } + end + end + + tests("inject body sha") do + returns(@signer.signature_parameters({:query => {'a' => 'foo', 'b' => 'foo'}, :headers => {'Host' => 'host.foo.com', 'Date' => 'Mon, 09 Sep 2011 23:36:00 GMT'}, :method => :get, :path => '/'}, @now, 'STREAMING-Aws4-HMAC-SHA256-PAYLOAD')) do + { + 'X-Amz-Algorithm' => 'Aws4-HMAC-SHA256', + 'X-Amz-Credential' => 'AKIDEXAMPLE/20110909/us-east-1/host/aws4_request', + 'X-Amz-SignedHeaders' => 'date;host', + 'X-Amz-Signature' => '22c32bb0d0b859b94839de4e9360bca1806e73d853f5f97ae0d849f0bdf42fb0' + } + end + end + + Fog::Time.now = ::Time.now +end diff --git a/tests/signed_params_tests.rb b/tests/signed_params_tests.rb new file mode 100644 index 000000000..ed42303ae --- /dev/null +++ b/tests/signed_params_tests.rb @@ -0,0 +1,17 @@ +# encoding: utf-8 + +Shindo.tests('Aws | signed_params', ['aws']) do + returns( Fog::AWS.escape( "'Stöp!' said Fred_-~./" ) ) { "%27St%C3%B6p%21%27%20said%20Fred_-~.%2F" } + + tests('Unicode characters should be escaped') do + unicode = ["00E9".to_i(16)].pack("U*") + escaped = "%C3%A9" + returns( escaped ) { Fog::AWS.escape( unicode ) } + end + + tests('Unicode characters with combining marks should be escaped') do + unicode = ["0065".to_i(16), "0301".to_i(16)].pack("U*") + escaped = "e%CC%81" + returns( escaped ) { Fog::AWS.escape( unicode ) } + end +end diff --git a/tests/storage_tests.rb b/tests/storage_tests.rb new file mode 100644 index 000000000..f0bb32bec --- /dev/null +++ b/tests/storage_tests.rb @@ -0,0 +1,7 @@ +# encoding: utf-8 + +Shindo.tests('Aws Storage | escape', ['aws']) do + tests('Keys can contain a hierarchical prefix which should not be escaped') do + returns( Fog::Storage::AWS.new.send(:escape, "key/with/prefix") ) { "key/with/prefix" } + end +end