Create spot instance by API with non-default VPC in ruby API - ruby

We use Ruby AWS-SDK version 2 for creating spot request that creates instance in default VPC.
We Like to create spot request with non-default VPC.
How can we pass non-default VPC in create spot request?
{
:spot_price => spot_price,
:type => 'one-time',
:instance_count => 1,
:launch_group => role,
:launch_specification => {
:image_id => image_id,
:instance_type => instance_type,
placement: {
availability_zone: zone
},
:security_groups => [security_group],
block_device_mappings: [{
device_name: "/dev/sda1",
ebs: {
delete_on_termination: true
}
}
]
}
}
where I can pass VPC ID or which attribute I need to add to create spot request in different VPC.
http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#request_spot_instances-instance_method

Related

How do I supply different conditions based on a parameter in an IAM Role CloudFormation Template

I'm writing a CloudFormation template for an IAM role that I will assume through STS. I need to add a condition where a key equals a value, where both the key and value depends on a "Stage" parameter. The value I've been able to programmatically change depending on the parameter, but all my attempts to change the key based on Stage have failed.
I've tried both using a map and !FindInMap to get the correct key, as well as tried to construct a condition with both cases using !If.
In the first case...
Mappings:
Constants:
beta:
Id: "beta.example.com"
Endpoint: "beta-link.example.com/api/oauth2/v2:aud"
prod:
Id: "example.com"
Endpoint: "link.example.com/api/oauth2/v2:aud"
AssumeRolePolicyDocument:
Statement:
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
!FindInMap [Constants, !Ref Stage, Endpoint]:
- !FindInMap [Constants, !Ref Stage, Id]
... I got an error: map keys must be strings; received a map instead
In the second case...
AssumeRolePolicyDocument:
Statement:
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
!If
- !Equals [!Ref Stage, prod]
- StringEquals:
"link.example.com/api/oauth2/v2:aud": "example.com"
- StringEquals:
"beta-link.example.com/api/oauth2/v2:aud": "beta.example.com"
...I got another error: Template format error: Conditions can only be boolean operations on parameters and other conditions
In short, how can I specify a condition where both key and value depend on a parameter?
I have struggled around 8 hours continuously and finally found an answer to this problem.
Just for the viewers I would like to summarise the problem:
Problem Statement : As a infrastructure engineer, I want to write a cloudformation resource for AWS::IAM::Role which defines a AssumeRolePolicyDocument with a Condition clause where the key needs to be parameterised. Also another question is can we use intrinsic functions with Condition keys?
Answer: Yes, it is possible using an out of the box style. AssumeRolePolicyDocument is a String Type as per the AWS Cloudformation documentation for 'AWS::IAM::Role'. So instead of using YAML style data to the AssumeRolePolicyDocument property, just pass a raw JSON formatted Assumerole policy using Fn::Sub and use variables to replace the key without any issues or warnings. Below is an example that you can use. Its a complex use case that i was trying to solve but it shows how you can replace keys under a IAM Condition clause using !SUB,!Select etc.
ExampleAppRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !Sub ${Environment}-ExampleAppRole
AssumeRolePolicyDocument:
Fn::Sub:
- |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${id}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${clusterid}": "${serviceaccount}"
}
}
}
]
}
-
clusterid: !Join ["",[!Sub "oidc.eks.${AWS::Region}.amazonaws.com/id/",!Select [1, !Split ["//", !Select [0, !Split [".", !GetAtt Cluster.Endpoint]]]],":sub"]]
id: !Select [1, !Split ["//", !Select [0, !Split [".", !GetAtt Cluster.Endpoint]]]]
Region: !Sub ${AWS::Region}
serviceaccount: system:serviceaccount:default:awsiamroleexample
Path: /
ManagedPolicyArns:
- !Ref SnsPublishAccessPolicy
Let me know your thoughts in the comments section.
I don't think using intrinsic functions within an IAM policy condition element is allowed, I haven't seen any example of that. Condition element only takes a set of predefined keys. I think you can try the following template, it's a bit verbose but it should work. Template powered by cloudkast
{
"AWSTemplateFormatVersion":"2010-09-09",
"Description":"Template created by CloudKast",
"Parameters":{
},
"Mappings":{
},
"Conditions":{
"Prod":{
"Fn::Equals":[
{
"Ref":"Stage"
},
"prod"
]
},
"Dev":{
"Fn::Equals":[
{
"Ref":"Stage"
},
"dev"
]
}
},
"Resources":{
"ProdRole":{
"Properties":{
"AssumeRolePolicyDocument":{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"Stmt1567153169873",
"Action":[
"sts:AssumeRoleWithWebIdentity"
],
"Effect":"Allow",
"Resource":"arn:aws:iam::namespace::relativeid"
}
]
},
"RoleName":"ProdRole"
},
"Type":"AWS::IAM::Role",
"Condition":"Prod"
},
"DevRole":{
"Properties":{
"AssumeRolePolicyDocument":{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"Stmt1567153169873",
"Action":[
"sts:AssumeRoleWithWebIdentity"
],
"Effect":"Allow",
"Resource":"arn:aws:iam::namespace::relativeid"
}
]
},
"RoleName":"DevRole"
},
"Type":"AWS::IAM::Role"
}
},
"Outputs":{
}
}

boto3 ec2 create instance with a name

I am new to AWS and using boto3 to launch an instance. However, I notice that when I create the instance, the "Name" field is empty. So, the way I create it is as follows:
def create_instance(ami, instance_type, device_name, iam_role, volume_type,
volume_size,
security_groups, key_name, user_data):
s = boto3.Session(region_name="eu-central-1")
ec2 = s.resource('ec2')
res = ec2.create_instances(
IamInstanceProfile={'Name': iam_role},
ImageId=ami,
InstanceType=instance_type,
SecurityGroupIds=security_groups,
KeyName=key_name,
UserData=user_data,
MaxCount=1,
MinCount=1,
InstanceInitiatedShutdownBehavior='terminate',
BlockDeviceMappings=[{
'DeviceName': device_name,
'Ebs': {
'DeleteOnTermination': True,
'VolumeSize': volume_size,
'VolumeType': volume_type
}
}]
)
instance = res[0]
while instance.state['Name'] == 'pending':
time.sleep(5)
instance.load()
return instance.public_ip_address, instance.public_dns_name
There does not seem to be a simple way to specify the name of the launched instance. How can one do this?
Put a tag with key Name with your instance name as a value.
TagSpecifications=[
{
'ResourceType': 'instance',
'Tags': [
{
'Key': 'Name',
'Value': '<What you want>'
},
]
},
],

How to constraint a route with a specific role in my case with vue-auth?

I develop my first Laravel application with Vue-js in SPA.
I try to forbid access to a route (view-router) through a role.
For roles, I use the spatie/laravel-permission package.
I set up view-auth rolesVar like this:
const config = {
rolesVar: 'roles',
…
}
Here is an example of a user in json
{
"status":"success",
"data":{
"id":1,
"first_name":"John",
"last_name":"Doe",
"email":"john#Doe",
"created_at":"2019-07-11 11:20:20",
"updated_at":"2019-07-11 11:20:20",
"all_permissions":[
],
"can":[
],
"permissions":[
],
"roles":[
{
"id":1,
"name":"super-admin",
"guard_name":"api",
"created_at":"2019-07-11 11:20:20",
"updated_at":"2019-07-11 11:20:20",
"pivot":{
"model_id":1,
"role_id":1,
"model_type":"App\\Models\\User"
},
"permissions":[
]
}
]
}
}
I try to force my role like this, but it does not work. I am redirected to / 403 (as requested).
I conclude that he does not take my role.
{
path: '/admin',
name: 'admin.dashboard',
component: AdminDashboard,
meta: {
auth: {
roles: { name: 'super-admin' },
redirect: { name: 'login' },
forbiddenRedirect: { path: '/403' }
}
}
},
I think it's because I have several json objects in "roles" but I don't know what to call it for it to work
Thanks for your help !
use server side security instead of client side like this
Route::group(['middleware' => ['permission:permission1|permission2']], function () {
Route::get('/protected_URL',function(){
return "I can only access this if i only have permission1 and permission2";
});
});
this was only authenticated user and user having "permission1" and "permission2" have access to this page, otherwise it will thought access denied error where you can easily catch this error with axios and display Access Denied message

Mongodb ruby driver: edit Collection::View instance filter

When I create Collection::View instance with:
client = Mongo::Client.new('mongodb://127.0.0.1:27017/test')
view = client[:users].find( { name: "Sally" } )
=> #<Mongo::Collection::View:0x69824029475340 namespace='test.users' #filter={"name" => "Sally"} #options={}>
How I can change filter hash of this instance later? This does not work:
view.filter.merge!("age" => 30)
=> #FrozenError: can't modify frozen BSON::Document
I don't think you can. .filter is a method which takes arguments. It is not a hash.
See examples
and also search the code
However you might be able to do something like:
view = lambda { |hash| client[:users].find(hash) }
search_params = { name: "Sally" }
view.(search_params)
view.(search_params.merge!({foo: 'bar'}))

Saving Point to a Google Fitness API (fitness.body.write)

Im trying to save a Point with float value into fitness.body.
Getting value is not a problem, while saving a new point causes 403. No permission to modify data for this source.
Im using DataSetId derived:com.google.weight:com.google.android.gms:merge_weight to find point and read value, and raw:com.google.weight:com.google.android.apps.fitness:user_input to insert data.
.
Here is a workflow using Ruby and google-api-ruby-client:
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'pry'
# Initialize the client.
client = Google::APIClient.new(
:application_name => 'Example Ruby application',
:application_version => '1.0.0'
)
fitness = client.discovered_api('fitness')
# Load client secrets from your client_secrets.json.
client_secrets = Google::APIClient::ClientSecrets.load
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/fitness.body.write',
'https://www.googleapis.com/auth/fitness.activity.write',
'https://www.googleapis.com/auth/fitness.location.write']
)
client.authorization = flow.authorize
Forming my new data Point:
dataSourceId = 'raw:com.google.weight:com.google.android.apps.fitness:user_input'
startTime = (Time.now-1).to_i # 1 Second ago
endTime = (Time.now).to_i
metadata = {
dataSourceId: dataSourceId,
maxEndTimeNs: "#{startTime}000000000", # Faking nanoseconds with tailing zeros
minStartTimeNs: "#{endTime}000000000",
point: [
{
endTimeNanos: "#{endTime}000000000",
startTimeNanos: "#{startTime}000000000",
value: [
{ fpVal: 80 }
]
}
]
}
Attempting to save the point:
result = client.execute(
:api_method => fitness.users.data_sources.datasets.patch,
:body_object => metadata,
:parameters => {
'userId' => "me",
'dataSourceId' => dataSourceId,
'datasetId' => "#{Time.now.to_i-1}000000000-#{(Time.now).to_i}000000000"
}
)
And as I indicated previously im getting 403. No permission to modify data for this source
#<Google::APIClient::Schema::Fitness::V1::Dataset:0x3fe78c258f60 DATA:{"error"=>{"er
rors"=>[{"domain"=>"global", "reason"=>"forbidden", "message"=>"No permission to modif
y data for this source."}], "code"=>403, "message"=>"No permission to modify data for
this source."}}>
I believe, I selected all required permissions in the scope. I tried submitting the point to both accessible datasetid's for fitness.body.
Please let me know if im doing anything wrong here.
Thank you!
I encountered the same situation, turns out you can NOT insert data points directly into the datasource "raw:com.google.weight:com.google.android.apps.fitness:user_input". From the name, one might guess out this datasource is reserved. So the workaround is to add your own datasource, note should with dataType.name="com.google.weight", like this:
{
"dataStreamName": "xxxx.body.weight",
"dataType": {
"field": [
{
"name": "weight",
"format": "floatPoint"
}
],
"name": "com.google.weight"
},
"dataQualityStandard": [],
"application": {
"version": "1",
"name": "Foo Example App",
"detailsUrl": "http://example.com"
},
"device": {
"model": "xxxmodel",
"version": "1",
"type": "scale",
"uid": "xxx#yyy",
"manufacturer": "xxxxManufacturer"
},
"type": "derived"
}
then after the successful creation, you can use this datasource(datastream id) to insert your own data points, and then the inserted data points will also be included in the datasource "derived:com.google.weight:com.google.android.gms:merge_weight" when you do the querying with suffix "dataPointChanges".
Try adding an Authorization header:
result = client.execute(
:api_method => fitness.users.data_sources.datasets.patch,
:headers => {'Authorization' => 'Bearer YOUR_AUTH_TOKEN'},
:body_object => metadata,
:parameters => {
'userId' => "me",
'dataSourceId' => dataSourceId,
'datasetId' => "#{Time.now.to_i-1}000000000-#{(Time.now).to_i}000000000"
}
)

Resources