how to restart instance group via python google cloud library - python

I am not able to find any code sample or relevant documentation on python library for google cloud
Want to restart managed instance groups all vms via cloud function.
To list instances I am using something like this
import googleapiclient.discovery
def list_instances(compute, project, zone):
result = compute.instances().list(project=project, zone=zone).execute()
return result['items'] if 'items' in result else None
in requirement file I have
google-api-python-client==2.31.0
google-auth==2.3.3
google-auth-httplib2==0.1.0
From command line this is possible via SDK ->
https://cloud.google.com/sdk/gcloud/reference/compute/instance-groups/managed/rolling-action/restart
gcloud compute instance-groups managed rolling-action restart NAME [--max-unavailable=MAX_UNAVAILABLE] [--region=REGION | --zone=ZONE] [GCLOUD_WIDE_FLAG …]
But in python I am not able to write any code.

This is an incomplete answer since the python docs are pretty unreadable to me.
Looking at the gcloud cli code (which I couldn't find an official repo for so I looked here),
the restart command is triggered by something called a "minimal action".
minimal_action = (client.messages.InstanceGroupManagerUpdatePolicy.
MinimalActionValueValuesEnum.RESTART)
In the Python docs, there's references to these fields in the applyUpdatesToInstances method.
So I think the relevant code is something similar to:
compute.instanceGroupManagers().applyUpdatesToInstances(
project=project,
zone=zone,
instanceGroupManager='NAME',
body={"allInstances": True, "minimalAction": "RESTART"},
)
There may or may not be a proper Python object for the body, the docs aren't clear.
And the result seems to be an Operation object of some kind, but I don't know if there's execute() method or not.

This is confusing, because gcloud compute instance-groups managed rolling-action is syntactic sugar that does two things:
It turns on Proactive updater, by setting appropriate UpdatePolicy on the InstanceGroupManager resource
And it changes version name on the same resource to trigger an update.
It is covered in the docs in https://cloud.google.com/compute/docs/instance-groups/rolling-out-updates-to-managed-instance-groups#performing_a_rolling_replace_or_restart
Compare the gcloud and API tabs to get the idea.
Unfortunately I am illiterate in Python, so I am not able to translate it into Python code :(.

Using the documentation that #Grzenio provided, use patch() method to restart the instance group. See patch documentation to check its parameters.
This could be written in python using the code below. I provided the required parameters project,zone,instanceGroupManager and body. The value of body is from the example in the documentation.
import googleapiclient.discovery
import json
project = 'your-project-id'
zone = 'us-central1-a' # the zone of your instance group
instanceGroupManager = 'instance-group-1' # instance group name
body = {
"updatePolicy": {
"minimalAction": "RESTART",
"type": "PROACTIVE"
},
"versions": [{
"instanceTemplate": "global/instanceTemplates/instance-template-1",
"name": "v2"
}]
}
compute = googleapiclient.discovery.build('compute', 'v1')
rolling_restart = compute.instanceGroupManagers().patch(
project=project,
zone=zone,
instanceGroupManager=instanceGroupManager,
body=body
)
restart_operation = rolling_restart.execute() # execute the request
print(json.dumps(restart_operation,indent=2))
This will return an operation object and the instance group should restart in the rolling fashion:
{
"id": "3206367254887659944",
"name": "operation-1638418246759-5d221f9977443-33811aed-eed3ee88",
"zone": "https://www.googleapis.com/compute/v1/projects/your-project-id/zones/us-central1-a",
"operationType": "patch",
"targetLink": "https://www.googleapis.com/compute/v1/projects/your-project-id/zones/us-central1-a/instanceGroupManagers/instance-group-1",
"targetId": "810482163278776898",
"status": "RUNNING",
"user": "serviceaccountused#your-project-id.iam.gserviceaccount.com",
"progress": 0,
"insertTime": "2021-12-01T20:10:47.654-08:00",
"startTime": "2021-12-01T20:10:47.670-08:00",
"selfLink": "https://www.googleapis.com/compute/v1/projects/your-project-id/zones/us-central1-a/operations/operation-1638418246759-5d221f9977443-33811aed-eed3ee88",
"kind": "compute#operation"
}

Related

YouTube API subscriber count incorrect because of channels with the same name

Code:
import requests
import json
key = 'key' #api key
url = 'https://www.googleapis.com/youtube/v3/channels?part=statistics&key='+ key +'&forUsername='
youtuber = input('What\'s the name of the youtuber: ') #get youtuber name
url += youtuber.lower() #youtuber name all lowercase
r = requests.get(url) #get data from youtuber channel webpage
try:
subs = json.loads(r.text)['items'][0]['statistics']['subscriberCount']
except:
print('Your youtuber doesn\'t exist ):')
exit()
print(youtuber,"has",subs,"subscribers! Woohoo!")
This is okay:
Input: Google
Output: Google has 9640000 subscribers! Woohoo!
This is not:
Input: Markiplier
Output: Markiplier has 84900 subscribers! Woohoo! (Actually, his main channel has 27.8M subscribers)
I run into the unfortunate issue of channels with the same name. How do I prevent this?
You have to acknowledge the following peculiarity of YouTube site: it permits (by design) that the very same name -- in your case Markiplier -- to be a channel's custom URL and, at the same time, to be the (legacy) user name of another channel.
Please read the first few paragraphs of my answer to a very much related question. From there, you'll get a pretty good idea about the difference between the two (sometimes confusing) concepts: channel user name and channel custom URL.
Concretely, if you'll make use of my Python3 public script youtube-search.py, you'll see that there are two different channels that exhibit the behavior I just described w.r.t. the name Markiplier:
$ python3 youtube-search.py --user-name Markiplier
UCxubOASK0482qC5psq89MsQ
$ python3 youtube-search.py --custom-url Markiplier
UC7_YxT-KID8kRbqZo7MyscQ
Note that youtube-search.py requires a valid API key to be passed to it as argument of the command line option --app-key or, otherwise, passed on as the environment variable YOUTUBE_DATA_APP_KEY. (Use the command line option --help for brief helping info.)
A further Channels.list API endpoint query on the following URL:
https://www.googleapis.com/youtube/v3/channels?id=UCxubOASK0482qC5psq89MsQ,UC7_YxT-KID8kRbqZo7MyscQ&part=id,snippet,statistics&fields=items(id,snippet(title,description,customUrl),statistics(subscriberCount))&maxResults=2&key=...
will confirm the difference you've experienced:
{
"items": [
{
"id": "UCxubOASK0482qC5psq89MsQ",
"snippet": {
"title": "markiplier",
"description": "I will no longer be updating this channel! All my new videos with be uploaded to markiplierGAME! Please re-subscribe on that channel to stay up-to-date on my videos!"
},
"statistics": {
"subscriberCount": "85000"
}
},
{
"id": "UC7_YxT-KID8kRbqZo7MyscQ",
"snippet": {
"title": "Markiplier",
"description": "Welcome to Markiplier! Here you'll find some hilarious gaming videos, original comedy sketches, animated parodies, and other bits of entertainment! If this sounds like your kind of channel then please Subscribe Today!\n\nTotal Charity Raised ▶ $3,000,000+",
"customUrl": "markiplier"
},
"statistics": {
"subscriberCount": "27800000"
}
}
]
}
Now, to make a summary of my points w.r.t. your question -- I run into the unfortunate issue of channels with the same name. How do I prevent this? --, I note the following:
Be sure what is that you look to obtain from the API: custom URLs and user names are different API concepts.
If you're trying to obtain info about a channel for which you have its user name, then use Channel.list endpoint queried with an appropriate forUsername parameter.
If you're trying to obtain info about a channel of given custom URL, then use the procedure and Python code I described in my answer to this question Obtaining a channel id from a youtube.com/c/xxxx link. Also be prepared for possible failure of that procedure (due to way the API is currently implemented, it may well happen that the procedure fails on certain valid custom URLs).

Smartsheet webhook subscope

I'm trying to create a webhook with subscope of a specific column in one of my sheets in python with the following code:
my_webhook = smartsheet_client.Webhooks.create_webhook(
smartsheet.models.Webhook({
'name': 'test 10',
'callbackUrl': 'https://my_web.com/webhook/test10',
'scope': 'sheet',
'scopeObjectId': 0000000000000000,
'subscope': {'columnIds': [0000000000000000]},
'events': ['*.*'],
'version': 1
}))
And when I get the successfully created webhook with its ID, the subscope is missing from the response.
Does anyone have a clue what am I doing wrong?
I'm not very familiar with the Smartsheet Python SDK, but in general, I often find it helpful to look at the integration test code in the SDK's GitHub repo whenever I have a question about how to implement a certain operation using the SDK. In this case, the integration test for webhooks in the SDK repo shows the following code for creating a webhook:
def test_create_webhook(self, smart_setup):
smart = smart_setup['smart']
webhook = smart.models.Webhook()
webhook.name = 'My Webhook'
webhook.callback_url = 'https://www.smartsheet.com'
webhook.scope = 'sheet'
webhook.scope_object_id = smart_setup['sheet'].id
webhook.events.append('*.*')
webhook.version = 1
webhook.subscope = smart.models.WebhookSubscope({'column_ids': [smart_setup['sheet'].columns[0].id]})
action = smart.Webhooks.create_webhook(webhook)
assert action.message == 'SUCCESS'
assert isinstance(action.result, smart.models.Webhook)
TestWebhooks.webhook = action.result
Notice specifically that the way the subscope property is being set differs from what you've posted above. I'd suggest trying to model your code more after this code, to see if you can achieve the desired outcome.
Your code is virtually identical to mine, and subscopes weren't working for me either. I upgraded from smartsheet-python-sdk pip package 2.86 to 2.105, and now my webhook gets set properly. I also verified that the subscope setting works, which greatly reduces the number of events I have to process.
Here is my code (although it's essentially the same as yours).
def createSheetWebhook(name, sheet_id, target, subscope=[]):
new_webhook = smartsheet_client.Webhooks.create_webhook(
smartsheet.models.Webhook({
"name": F"sheet changes for {name}",
"callbackUrl": target,
"scope": 'sheet',
"scopeObjectId": sheet_id,
"subscope": {
"columnIds": subscope
},
"events": ['*.*'],
"version": 1
})
)
return new_webhook.result.id

Intent to invoke another intent (without followup intents)

I have an intent called ContinueIntent and its event is named ContinueEvent.
I also have an intent called DummyIntent. I'm using Dialogflow V2.
I want the user to invoke DummyIntent. This then links to the webhook which returns a parameter value and then invokes ContinueIntent.
Please respond with the python/JSON which should be returned from the webhook. The question then is how do I change my existing webhook and JSON (shown below) to allow me to:
Invoke another intent
pass through a value
Current JSON:
{
"fulfillmentText": text,
"source": source
}
I read somewhere to add (but I don't know where and can't get it to work):
CLIENT_ACCESS_TOKEN = 'sdfghjkl34notreal567890dfghjkl'
ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN)
req = ai.event_request(apiai.events.Event("ContinueEvent"))
response = req.getResponse().read()
The solution was to change the JSON to the following:
"followupEventInput":{
"name":"ContinueEvent",
"parameters":{
"param": param_value
}
},

Why does Google Drive API returns incomplete response?

I'm using google-api-python-client to call the Google Drive API.
According to the API's spec, get should return a JSON with many fields. But my program only returns id, name, mimeType and kind as follows:
{
"id": <omitted>,
"name": "myfile.txt",
"mimeType": "text/plain",
"kind": "drive#file"
}
How do I get other metadata about a file using this API?
All right. I found the answer. The info on the spec page is incomplete. As pointed out in another page, the API calls accept a fields parameter which specify the fields to return.

ATDD Google App Engine with Python - Trouble with Keys

My approach to this question might be completely wrong, so please don't hesitate to correct it. I also added ATDD in the question title, because I am trying to test the output of my web api which is bigger than just a unit test.
I am using:
Google App Engine 1.7.1
GAE High Replication Datastore
Python 2.7.3
I setup my tests using the boilerplate code:
self.testbed = testbed.Testbed()
self.testbed.activate()
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=0)
self.testbed.init_datastore_v3_stub()
Then I call a mock object setup to setup my entities and persist them to the testbed datastore. I use a counter to add 5 artists with artist_id 1 - 5:
def add_mock_artist_with(self, artist_id, link_id, name):
new_artist = dto.Artist(key_name=str(artist_id),
name=name,
link_id= str(link_id))
new_artist.put()
My test is that my web api returns:
{
"artists": [
{
"artist": {
"name": "Artist 1",
"links": {
"self": {
"href": "https://my_server.com/artist/1/"
}
}
}
},
.
.
.
{
"artist": {
"name": "Artist 5",
"links": {
"self": {
"href": "https://my_server.com/artist/5/"
}
}
}
}
],
"links": {
"self": {
"href": "https://my_server.com/artists/"
}
}
}
Initially I thought that if I were to startup a new test bed every time I run the tests, I could count on my artists being entered sequentially into the data store and therefore would get ids 1 - 5. My tests passed initially, but over time started to fail because of ids not matching (I would get a link like: "href": "https://my_server.com/artist/78/"). I felt a little guilty relying on ids being generated sequentially, so I resolved to fix it. I stumbled upon the concept of a key being either a name or a generated id. I updated my templates for the returned JSON to use:
artist.key().id_or_name()
In the case of a mock object, I supplied the key name on construction with:
key_name=str(artist_id)
For non-mock construction, I did not include that line of code and let GAE assign the id.
Since my template used key().id_or_name() to output the property, all went well and the tests passed.
However, now when I test the return of an individual artist which would be available by following http://my_server.com/artist/5/, my test fails. To grab the artist out of the datastore, I use the following code:
def retrieve_artist_by(id):
artist = dto.Artist.get_by_id()
In production, this will work fine because it will all be id based. However, in my test, it is not finding anything because I have used the key_name=str(artist_id) in my mock construction, and the name is not the same as the id.
I was hoping for something similar to:
artist = dto.Artist.get_by_id_or_name()
Any ideas?
Perhaps not the answer you are looking for, but it's possible to find out if you are running on the production or deployment servers and execute a different code path.
In Python, how can I test if I'm in Google App Engine SDK?
http://code.google.com/appengine/docs/python/runtime.html#The%5FEnvironment
os.environ['SERVER_SOFTWARE'].startswith('Development')
Here is what I am using right now. I don't like it, but it should be performant in prod as I will be using generated ids. In test, if it doesn't find it by id, it will attempt to look up by name.
def retrieve_artist_by(id):
artist = dto.Artist.get_by_id(id)
if artist is None:
artist = dto.Artist.get_by_key_name(str(id))
return artist

Categories