AWS CloudWatch returns InvalidNextToken - amazon-web-services

I am trying to get some CloudWatch metrics using .NET SDK. The code that is seen below returns some data points but after returning about 20 data points it raises an Exception of InvalidNextToken.
private static void Main(string[] args)
{
Console.Clear();
var creds = new StoredProfileAWSCredentials();
var c = new AmazonCloudWatchClient(creds, RegionEndpoint.EUCentral1);
Task<GetMetricDataResponse> t = null;
string nextToken = null;
do
{
var req = new GetMetricDataRequest
{
EndTimeUtc = DateTime.UtcNow,
MaxDatapoints = 10,
StartTimeUtc = DateTime.UtcNow.AddHours(-1),
ScanBy = new ScanBy("TimestampDescending"),
NextToken = nextToken,
MetricDataQueries = new List<MetricDataQuery>
{
new MetricDataQuery
{
Id = "a" + Guid.NewGuid().ToString().Replace("-", ""),
MetricStat = new MetricStat
{
Stat = "Maximum",
Metric = new Metric
{
MetricName = "CPUUtilization",
Dimensions = new List<Dimension>
{
new Dimension
{
Name = "InstanceId",
Value = "i-04f27d16c91c70119"
}
},
Namespace = "AWS/EC2"
},
Period = 60,
Unit = StandardUnit.Percent
}
}
}
};
t = c.GetMetricDataAsync(req);
t.Wait();
var usage = t.Result;
if (usage.MetricDataResults.Any())
foreach (var r in usage.MetricDataResults)
foreach (var rValue in r.Values)
Console.WriteLine(Math.Round(rValue * 100));
nextToken = t.Result.NextToken;
} while (!string.IsNullOrEmpty(nextToken));
Console.ReadKey();
}
The exact Exception message is:
InvalidNextTokenException: The service returned an error with Error
Code InvalidNextToken and HTTP Body:
Sender
InvalidNextToken 795050a1-3bcd-4a44-9794-5becd0c4f5cf

For nextToken to work, you need to send the exact same request, with only the token changing between calls.
You have id, StartTimeUtc and EndTimeUtc changing between requests.
Initializing them before the loop should fix your problem.
Try something like this:
private static void Main(string[] args)
{
Console.Clear();
var creds = new StoredProfileAWSCredentials();
var c = new AmazonCloudWatchClient(creds, RegionEndpoint.EUCentral1);
Task<GetMetricDataResponse> t = null;
string nextToken = null;
var endTime = DateTime.UtcNow;
var startTime = endTime.AddHours(-1);
var id = "a" + Guid.NewGuid().ToString().Replace("-", "");
do
{
var req = new GetMetricDataRequest
{
EndTimeUtc = endTime,
MaxDatapoints = 10,
StartTimeUtc = startTime,
ScanBy = new ScanBy("TimestampDescending"),
NextToken = nextToken,
MetricDataQueries = new List<MetricDataQuery>
{
new MetricDataQuery
{
Id = id,
MetricStat = new MetricStat
{
Stat = "Maximum",
Metric = new Metric
{
MetricName = "CPUUtilization",
Dimensions = new List<Dimension>
{
new Dimension
{
Name = "InstanceId",
Value = "i-04f27d16c91c70119"
}
},
Namespace = "AWS/EC2"
},
Period = 60,
Unit = StandardUnit.Percent
}
}
}
};
t = c.GetMetricDataAsync(req);
t.Wait();
var usage = t.Result;
if (usage.MetricDataResults.Any())
foreach (var r in usage.MetricDataResults)
foreach (var rValue in r.Values)
Console.WriteLine(Math.Round(rValue * 100));
nextToken = t.Result.NextToken;
} while (!string.IsNullOrEmpty(nextToken));
Console.ReadKey();
}

Related

Use Aws4RequestSigner to sign PAAPI 5 Request

I'm trying to use Aws4RequestSigner in a VS2015 form to sign a search request to Amazon PAAPI.
https://www.nuget.org/packages/Aws4RequestSigner/
I get this response from the API:
{"__type":"com.amazon.paapi5#IncompleteSignatureException","Errors":[{"Code":"IncompleteSignature","Message":"The request signature did not include all of the required components. If you are using an AWS SDK, requests are signed for you automatically; otherwise, go to https://webservices.amazon.com/paapi5/documentation/sending-request.html#signing."}]}
private async void Form1_Load(object sender, EventArgs e)
{
_accessKey = "x";
_secretKey = "x";
_service = "ProductAdvertisingAPIv1";
_region = "us-east-1";
_requestUri = new Uri("https://webservices.amazon.com/paapi5/searchitems");
var payload = new
{
Keywords = "Harry",
Marketplace = "www.amazon.com",
PartnerTag = "x0d-20",
PartnerType = "Associates",
Resources = new string[] { "Images.Primary.Small", "ItemInfo.Title", "Offers.Listings.Price" },
SearchIndex = "All"
};
string jsonString = JsonConvert.SerializeObject(payload);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var xAmzDate = GetTimeStamp();
content.Headers.Add("content-encoding", "amz-1.0");
content.Headers.Add("x-amz-date", xAmzDate);
content.Headers.Add("x-amz-target", "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.SearchItems");
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = _requestUri,
Content = content
};
request.Headers.Host = "webservices.amazon.com";
var contentType = new MediaTypeHeaderValue("application/json");
contentType.CharSet = "utf-8";
request.Content.Headers.ContentType = contentType;
var signer = new AWS4RequestSigner(_accessKey, _secretKey);
request = await signer.Sign(request, _service, _region);
try
{
var client = new HttpClient();
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
}
// response.EnsureSuccessStatusCode();
txtDisplay.Text = await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
string error = ex.Message;
txtDisplay.Text = error;
}
}
private string GetTimeStamp()
{
return DateTime.UtcNow.ToString("yyyyMMdd\\THHmmss\\Z");
}
It could be that the headers are being added incorrectly or Aws4RequestSigner is simply outdated.

PowerBI Embedded: DeleteUserAsAdminAsync returns unauthorized

Receiving an unauthorized response when trying to remove a user from a workspace (group). I'm using the .Net SDK method DeleteUserAsAdminAsync. I tried the DeleteUserInGroupAsync method with the same result. I've had no trouble retrieving groups, reports, even adding users to groups using the same authentication code shown below. I'm quite stumped.
public async Task<ResultObject> RemoveUsersFromWorkspaces(List<PowerBIWorkspace> powerBIWorkspaces)
{
// Authenticate using created credentials
AuthenticationResult authenticationResult = null;
authenticationResult = await DoAuthentication("CustomerAppRegistration");
var tokenCredentials =
new TokenCredentials(authenticationResult.AccessToken, "Bearer");
using (var client = new PowerBIClient(
new Uri("https://api.powerbi.com/"), tokenCredentials))
{
try
{
foreach (var wksp in powerBIWorkspaces)
{
// Remove the user to the workspace.
await client.Groups.DeleteUserAsAdminAsync(new Guid(wksp.WorkspaceId), wksp.UserEmail);
}
}
catch (Exception ex)
{
var errorObject = new ResultObject();
errorObject.Success = false;
errorObject.ErrorMessage = ex.Message;
return errorObject;
}
}
var resultObject = new ResultObject();
resultObject.Success = true;
resultObject.ErrorMessage = "";
return resultObject;
}
private const string AuthorityFormat = "https://login.microsoftonline.com/{0}/v2.0";
private const string MSGraphScope = "https://analysis.windows.net/powerbi/api/.default";
private async Task<AuthenticationResult> DoAuthentication(string appRegistrationSection)
{
var config = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json").Build();
//var section = config.GetSection(nameof(AppRegistration));
var section = config.GetSection(appRegistrationSection);
var appRegistration = section.Get<AppRegistration>();
TenantID = appRegistration.TenantId;
ClientID = appRegistration.ClientId;
ClientSecret = appRegistration.ClientSecret;
IConfidentialClientApplication daemonClient;
daemonClient = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithAuthority(string.Format(AuthorityFormat, TenantID))
.WithClientSecret(ClientSecret)
.Build();
AuthenticationResult authResult =
await daemonClient.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();
return authResult;
}

Pass field from Droid project to PCL, Xamarin.Forms

I have an app that allows users to log in via facebook, once user enters their credentials - My api request saves the user onto the database and auto-generates a user token(This is unique to each user). In order to display user specific details once user logs in - the token needs to be referenced. I am trying to get this token to the PCL project but it returns null just for the token. When I tried passing another string like name, it passes the correct value. Any help will be much appreciated.Thanks
FacebookRender in droid:
public class FacebookRender : PageRenderer
{
public FacebookRender()
{
CustomerService customerService = new CustomerService();
String error;
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "",
scope: "",
authorizeUrl: new Uri("https://www.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("https://www.facebook.com/connect/login_success.html")
);
auth.Completed += async (sender, eventArgs) =>
{
try
{
if (eventArgs.IsAuthenticated)
{
await AccountStore.Create().SaveAsync(eventArgs.Account, "FacebookProviderKey");
var accessToken = eventArgs.Account.Properties["access_token"].ToString();
var expiresIn = Convert.ToDouble(eventArgs.Account.Properties["expires_in"]);
var expiryDate = DateTime.Now + TimeSpan.FromSeconds(expiresIn);
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me?fields=email,first_name,last_name,gender,picture"), null, eventArgs.Account);
var response = await request.GetResponseAsync();
var obj = JObject.Parse(response.GetResponseText());
var id = obj["id"].ToString().Replace("\"", "");
var name = obj["first_name"].ToString().Replace("\"", "");
var surname = obj["last_name"].ToString().Replace("\"", "");
var gender = obj["gender"].ToString().Replace("\"", "");
//var email = obj["email"].ToString().Replace("\"", "");
Customer.Customers cust = new Customer.Customers();
cust.Credentials = new Customer.Credentials();
cust.Name = name;
cust.Surname = surname;
cust.Email = "";
cust.MobilePhone = "";
cust.DOB = DateTime.Now;
cust.Number = "";
cust.City = "";
cust.Region = "";
cust.Country = "";
cust.DeviceToken = "sample";
cust.Credentials.SecretKey = "";
await customerService.AddCustomer(cust);
App.SaveToken(cust.Credentials.Token); - **//This is where I am passing the token**
App.NavigateToProfile(string.Format(name + surname));
}
else
{
App.NavigateToProfile("Invalid Login");
}
}
catch(Exception ex)
{
error = ex.Message;
}
};
activity.StartActivity(auth.GetUI(activity));
}
App.cs
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
public static void NavigateToProfile(string message)
{
App.Current.MainPage = (new Profile(message));
}
static string _Token;
public static string Token
{
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
AboutPage.cs - I am passing the token in a label just to see if it's passing
public partial class About : ContentPage
{
private Label _lbltoken;
public About()
{
//InitializeComponent();
Appearing += (object s, EventArgs a) => {
_lbltoken.Text = App.Token;
};
string tk = App.Token;
_lbltoken = new Label()
{
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Text = tk,
};
var stack = new StackLayout
{
VerticalOptions = LayoutOptions.StartAndExpand,
Children = { _lbltoken },
};
Content = stack;
}
}
You can use the MessagingCenter.
Messages may be sent as a result like a button click, a system event or some other incident. Subscribers might be listening in order to change the appearance of the user interface, save data or trigger some other operation.
More Info
I don't really now if its good idea use static fields in App class. Xamarin access all fields with service locator, App.Current.[property] I will suggest you try to change these fields to public
string _Token;
public string Token
{
get { return _Token; }
}
public void SaveToken(string token)
{
_Token = token;
}
and use it with App.Current.SaveToken(token) or App.Current.Token

Amazon Web service - signature

I've been receiving an error from Amazon web service - InvalidParameterValue
Either Action or Operation query parameter must be present.
I believe it is most likely due to the signature being incorrect as the XML document and Header matches that of a test I did in their scratchpad.
Does anything stand out as being incorrect?
Thanks,
Clare
private static string ConstructCanonicalQueryString(SortedDictionary<string, string> sortedParameters)
{
var builder = new StringBuilder();
if (sortedParameters.Count == 0)
{
builder.Append(string.Empty);
return builder.ToString();
}
foreach (var kvp in sortedParameters)
{
builder.Append(PercentEncodeRfc3986(kvp.Key));
builder.Append("=");
builder.Append(PercentEncodeRfc3986(kvp.Value));
builder.Append("&");
}
var canonicalString = builder.ToString();
return canonicalString.Substring(0, canonicalString.Length - 1);
}
private static string PercentEncodeRfc3986(string value)
{
value = HttpUtility.UrlEncode(string.IsNullOrEmpty(value) ? string.Empty : value, Encoding.UTF8);
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
value = value.Replace("'", "%27")
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("*", "%2A")
.Replace("!", "%21")
.Replace("%7e", "~")
.Replace("+", "%20")
.Replace(":", "%3A");
var sbuilder = new StringBuilder(value);
for (var i = 0; i < sbuilder.Length; i++)
{
if (sbuilder[i] != '%')
{
continue;
}
if (!char.IsLetter(sbuilder[i + 1]) && !char.IsLetter(sbuilder[i + 2]))
{
continue;
}
sbuilder[i + 1] = char.ToUpper(sbuilder[i + 1]);
sbuilder[i + 2] = char.ToUpper(sbuilder[i + 2]);
}
return sbuilder.ToString();
}
public string SignRequest(Dictionary<string, string> parametersUrl, Dictionary<string, string>
parametersSignture)
{
var secret = Encoding.UTF8.GetBytes(parametersSignture["Secret"]);
var signer = new HMACSHA256(secret);
var pc = new ParamComparer();
var sortedParameters = new SortedDictionary<string, string>(parametersUrl, pc);
var orderedParameters = ConstructCanonicalQueryString(sortedParameters);
var builder = new StringBuilder();
builder.Append(parametersSignture["RequestMethod"])
.Append(" \n")
.Append(parametersSignture["EndPoint"])
.Append("\n")
.Append("/\n")
.Append(orderedParameters);
var stringToSign = builder.ToString();
var toSign = Encoding.UTF8.GetBytes(stringToSign);
var sigBytes = signer.ComputeHash(toSign);
var signature = Convert.ToBase64String(sigBytes);
return signature.Replace("=", "%3D").Replace("/", "%2F").Replace("+", "%2B");
}
public class ParamComparer : IComparer<string>
{
public int Compare(string p1, string p2)
{
return string.CompareOrdinal(p1, p2);
}
}
The issue was that the Action wasn't included correctly into the Request

Getting VMWare DataStore inventory data (inventory traversal)

I'm attempting to get typical properties (capacity, free space, name) from the DataStores in my VMware ESXi server. I'm having trouble getting the TraversalSpec, ObjectSpec and PropertySpecs.
Can someone please tell me what I'm doing wrong?
public void GetDataStoreValues()
{
PropertyFilterSpec spec = GetDataStoreQuery();
ObjectContent[] objectContent = _service.RetrieveProperties(_sic.propertyCollector, new[] { spec } );
foreach (ObjectContent content in objectContent)
{
if (content.obj.type == "DataStore")
{
//... get values
}
}
}
private PropertyFilterSpec GetDataStoreQuery()
{
try
{
// Traversal to get to the host from ComputeResource
TraversalSpec tSpec = new TraversalSpec
{
name = "HStoDS",
type = "HostSystem",
path = "dataStore",
skip = false
};
// Now create Object Spec
var objectSpec = new ObjectSpec
{
obj = _sic.rootFolder,
skip = true,
selectSet = new SelectionSpec[] { tSpec }
};
var objectSpecs = new[] { objectSpec };
// Create PropertyFilterSpec using the PropertySpec and ObjectPec
// created above.
// Create Property Spec
string[] propertyArray = new[] {
"summary.capacity"
,"summary.freeSpace"
,"summary.name"
};
var propertySpec = new PropertySpec
{
all = true,
pathSet = propertyArray,
type = "DataStore"
};
var propertySpecs = new[] { propertySpec };
var propertyFilterSpec = new PropertyFilterSpec
{
propSet = propertySpecs,
objectSet = objectSpecs
};
return propertyFilterSpec;
}
catch (Exception)
{
}
return null;
}
Also, are object type names case sensitive? I seem to see all sorts of cases when I look at samples.
Thanks for any suggestions.
First question: You can use the following code to get properties of DataStore. I tested this code on vCenter 5.1
public void Test()
{
var properties = GetProperties(
new ManagedObjectReference { type = "Datastore", Value = "<your_datastore_key>" },
new[] {"summary.capacity", "summary.freeSpace", "summary.name"});
}
private List<DynamicProperty> GetProperties(ManagedObjectReference objectRef, string[] properties)
{
var typesAndProperties = new Dictionary<string, string[]> { { objectRef.type, properties } };
var objectContents = RetrieveResults(typesAndProperties, new List<ManagedObjectReference> { objectRef });
return ExtractDynamicProperties(objectRef, objectContents);
}
private List<ObjectContent> RetrieveResults(Dictionary<string, string[]> typesAndProperties, List<ManagedObjectReference> objectReferences)
{
var result = new List<ObjectContent>();
var tSpec = new TraversalSpec { path = "view", skip = false };
var oSpec = new ObjectSpec { skip = true, selectSet = new SelectionSpec[] { tSpec } };
oSpec.obj = service.CreateListView(serviceContent.viewManager, objectReferences.ToArray());
tSpec.type = "ListView";
var fSpec = new PropertyFilterSpec
{
objectSet = new[] { oSpec },
propSet = typesAndProperties.Keys.Select(typeName => new PropertySpec { type = typeName, pathSet = typesAndProperties[typeName] }).ToArray()
};
PropertyFilterSpec[] pfs = { fSpec };
var retrieveResult = service.RetrievePropertiesEx(serviceContent.propertyCollector, pfs, new RetrieveOptions());
if (retrieveResult != null)
{
result.AddRange(retrieveResult.objects);
while (!String.IsNullOrEmpty(retrieveResult.token))
{
retrieveResult = service.ContinueRetrievePropertiesEx(serviceContent.propertyCollector, retrieveResult.token);
result.AddRange(retrieveResult.objects);
}
service.DestroyView(oSpec.obj);
}
return result;
}
private static List<DynamicProperty> ExtractDynamicProperties(ManagedObjectReference objectRef, IEnumerable<ObjectContent> objectContents)
{
var result = new List<DynamicProperty>();
foreach (var objectContent in objectContents)
{
if (objectContent.propSet == null) continue;
if (objectContent.obj == null) continue;
if (objectContent.obj.type != objectRef.type || objectContent.obj.Value != objectRef.Value) continue;
result.AddRange(objectContent.propSet);
}
return result;
}
How to run the sample:
Initialize the service by object of VimService class and the serviceContent by object of ServiceContent class.
Login to vCenter or ESX using service.
Replace <your_datastore_key> with Key of your datastore. You can use the Managed Object Browser to find keys of their datastores. To get a description of datastore object, go to following links in MOB: content -> rootFolder -> childEntity -> datastoreFolder -> childEntity. Value of "Managed Object ID" on top of page is correct Key (like datastore-46).
Second question: Yes, the type of ManagedObjectReference is case sensitive.