How to prepare Pub/Sub emulator for tests? - google-cloud-platform

I start the gcloud sdk docker
docker run -ti --rm --expose=8085 -p 8085:8085 google/cloud-sdk:latest
then i run:
gcloud beta emulators pubsub start --project=my-project --host-port=0.0.0.0:8085
then stop the sever and then:
gcloud beta emulators pubsub env-init
gives:
export PUBSUB_EMULATOR_HOST=0.0.0.0:8085
but there is no project id. How can I setup project for tests? How can i create topics and subscriptions?
version:
gcloud version
gives:
Google Cloud SDK 236.0.0
...
pubsub-emulator 2019.02.22

You are launching pubsub emulator with project my-project in your 2nd command. Once this is running, don't kill it, leave it running.
To create the topics and subscriptions, you have to use one of the SDKs. I created a demo project that does this using the Java SDK: https://github.com/nhartner/pubsub-emulator-demo/
The relevant code is this:
#Component
public class TestPubSubConfig {
private final TransportChannelProvider channelProvider;
private final CredentialsProvider credentialsProvider;
private String projectId;
private String topicName = "test-topic";
private String subscriptionName = "test-subscription";
TestPubSubConfig(#Autowired #Value("${spring.cloud.gcp.pubsub.emulator-host}") String emulatorHost,
#Autowired #Value("${spring.cloud.gcp.project-id}") String projectId) throws IOException {
this.projectId = projectId;
ManagedChannel channel = ManagedChannelBuilder.forTarget(emulatorHost).usePlaintext().build();
channelProvider = FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));
credentialsProvider = NoCredentialsProvider.create();
createTopic(topicName);
createSubscription(topicName, subscriptionName);
}
#Bean
public Publisher testPublisher() throws IOException {
return Publisher.newBuilder(ProjectTopicName.of(projectId, topicName))
.setChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build();
}
private void createSubscription(String topicName, String subscriptionName) throws IOException {
ProjectTopicName topic = ProjectTopicName.of(projectId, topicName);
ProjectSubscriptionName subscription = ProjectSubscriptionName.of(projectId, subscriptionName);
try {
subscriptionAdminClient()
.createSubscription(subscription, topic, PushConfig.getDefaultInstance(), 100);
}
catch (AlreadyExistsException e) {
// this is fine, already created
}
}
private void createTopic(String topicName) throws IOException {
ProjectTopicName topic = ProjectTopicName.of(projectId, topicName);
try {
topicAdminClient().createTopic(topic);
}
catch (AlreadyExistsException e) {
// this is fine, already created
}
}
private TopicAdminClient topicAdminClient() throws IOException {
return TopicAdminClient.create(
TopicAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider).build());
}
private SubscriptionAdminClient subscriptionAdminClient() throws IOException {
return SubscriptionAdminClient.create(SubscriptionAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build());
}
}

A possible gotchya we uncovered while working with the Pub/Sub emulator is that the documentation says:
In this case, the project ID can be any valid string; it does not
need to represent a real GCP project because the Cloud Pub/Sub
emulator runs locally.
any valid string in this context is not any string, but specifically a valid one, meaning it looks like a valid GC Project Id. In our testing this was specifically strings that match the REGEX pattern:
/^[a-z]-[a-z]-\d{6}$/
Once supplied with a valid project ID, the emulator works as advertised. If you have a sandbox project in GC you can use that ID or you can make up your own that matches that pattern. Once you got that far you can follow the remainder of the Testing apps locally with the emulator documentation.

Related

Spring Boot Video Streaming from S3 Bucket

I want to create a youtube like Video streaming application but in a small scale. I am using Spring boot for backend rest endpoints and amazon S3 bucket for storing video files. I am able to upload and download video files to S3 bucket. But I am confused in streaming side. I want to show those video files in jsp page to play. I heard about Aws video on demand, aws kinesis, etc. Can someone suggest me or share some link which will be the best approach to follow for video streaming with spring boot. Or is there any other service apart from aws services which can be useful in this scenario. I am totally confused. Please help me out. Thank you.
I have created a sample project for streaming the AWS s3 resources using spring boot.
You can set a controller with mapping as required.
For this demo code the endpoint is http://localhost:port/bucket_name/object_key
#RestController("/")
public class ApiController {
#Value("${aws.region}")
private String awsRegion;
#GetMapping(value = "/**", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
public ResponseEntity<StreamingResponseBody> getObject(HttpServletRequest request) {
try {
AmazonS3 s3client = AmazonS3ClientBuilder.standard().withRegion(awsRegion).build();
String uri = request.getRequestURI();
String uriParts[] = uri.split("/", 2)[1].split("/", 2);
String bucket = uriParts[0];
String key = uriParts[1];
System.out.println("Fetching " + uri);
S3Object object = s3client.getObject(bucket, key);
S3ObjectInputStream finalObject = object.getObjectContent();
final StreamingResponseBody body = outputStream -> {
int numberOfBytesToWrite = 0;
byte[] data = new byte[1024];
while ((numberOfBytesToWrite = finalObject.read(data, 0, data.length)) != -1) {
outputStream.write(data, 0, numberOfBytesToWrite);
}
finalObject.close();
};
return new ResponseEntity<StreamingResponseBody>(body, HttpStatus.OK);
} catch (Exception e) {
System.err.println("Error "+ e.getMessage());
return new ResponseEntity<StreamingResponseBody>(HttpStatus.BAD_REQUEST);
}
}
}
You need to use StreamingResponseBody in your ResponseEntity.
If you need a ready to use microservice feel free to explore the github project s3-streamer I wrote for very same purpose.

AWS SNS: Not sending sms to phone number

I am trying a small demo for sending SMS to numbers here in India. I used following code snippet but not working.
public void send(String to, String textBody) {
AWSCredentials awsCredentials;
awsCredentials = new EnvironmentVariableCredentialsProvider().getCredentials();
AmazonSNSClient snsClient = new AmazonSNSClient(awsCredentials);
PublishResult result = snsClient
.publish(new PublishRequest().withMessage(textBody)
.withPhoneNumber("+9195355*****"));
System.out.println(result);
}
I am not able to figure out what is missing?
Since you've confirmed that sending SMS using the SNS console,the messages are delivered successfully then this seems to suggest that there could be an issue with the provided code snippet!
I've modified your code snippet slightly and I've confirmed the following code snippet to be working without issues :
public static void main(String[] args) {
ProfileCredentialsProvider creds = new ProfileCredentialsProvider("syumaK");
AmazonSNS snsClient = AmazonSNSClientBuilder.standard().withCredentials(creds).withRegion("us-east-1").build();
String textBody = "My test SMS message from SNS";
String to = "+0123456789";
send(snsClient, to, textBody);
}
public static void send(AmazonSNS snsClient, String to, String textBody) {
try {
PublishResult result = snsClient
.publish(new PublishRequest()
.withMessage(textBody)
.withPhoneNumber(to));
System.out.println(result);
LOGGER.info("Message send with id {}."+ result.getMessageId());
} catch (AmazonSNSException e) {
LOGGER.info("Got an exception. " + e.getMessage())
}
}
Troubleshooting Steps:
-If using ProfileCredentialsProvider works just like above, consider switching back to EnvironmentVariableCredentialsProvider or using BasicAWSCredentials provider and check if you observe any success/failure?
I have tested the above code snippet using the following environment spec:
OS : Ubuntu 16.04
aws region: us-east-1
aws-java-sdk: "1.11.723"

AWS Java SDK - Running a command using SSM on EC2 instances

I could not find any examples of this online, nor could I find the documentation explaining how to do this. Basically I have a list of Windows EC2 instances and I need to run the quser command in each one of them to check how many users are logged on.
It is possible to do this using the AWS Systems Manager service and running the AWS-RunPowerShellScript command. I only found examples using the AWS CLI, something like this:
aws ssm send-command --instance-ids "instance ID" --document-name "AWS-RunPowerShellScript" --comment "Get Users" --parameters commands=quser --output text
But how can I accomplish this using the AWS Java SDK 1.11.x ?
#Alexandre Krabbe it's more than a year before you asked this question. So not sure the answer will help you. But I was trying to do the same recently and that led me to this unanswered question. I ended up solving the problem and thought my answer could help other people facing the same problem. Here is a code snippet for the same:
public void runCommand() throws InterruptedException {
//Command to be run
String ssmCommand = "ls -l";
Map<String, List<String>> params = new HashMap<String, List<String>>(){{
put("commands", new ArrayList<String>(){{ add(ssmCommand); }});
}};
int timeoutInSecs = 5;
//You can add multiple command ids separated by commas
Target target = new Target().withKey("InstanceIds").withValues("instance-id");
//Create ssm client.
//The builder could be chosen as per your preferred way of authentication
//use withRegion for specifying your region
AWSSimpleSystemsManagement ssm = AWSSimpleSystemsManagementClientBuilder.standard().build();
//Build a send command request
SendCommandRequest commandRequest = new SendCommandRequest()
.withTargets(target)
.withDocumentName("AWS-RunShellScript")
.withParameters(params);
//The result has commandId which is used to track the execution further
SendCommandResult commandResult = ssm.sendCommand(commandRequest);
String commandId = commandResult.getCommand().getCommandId();
//Loop until the invocation ends
String status;
do {
ListCommandInvocationsRequest request = new ListCommandInvocationsRequest()
.withCommandId(commandId)
.withDetails(true);
//You get one invocation per ec2 instance that you added to target
//For just a single instance use get(0) else loop over the instanced
CommandInvocation invocation = ssm.listCommandInvocations(request).getCommandInvocations().get(0);
status = invocation.getStatus();
if(status.equals("Success")) {
//command output holds the output of running the command
//eg. list of directories in case of ls
String commandOutput = invocation.getCommandPlugins().get(0).getOutput();
//Process the output
}
//Wait for a few seconds before you check the invocation status again
try {
TimeUnit.SECONDS.sleep(timeoutInSecs);
} catch (InterruptedException e) {
//Handle not being able to sleep
}
} while(status.equals("Pending") || status.equals("InProgress"));
if(!status.equals("Success")) {
//Command ended up in a failure
}
}
In SDK 1.11.x , use sth like:
val waiter = ssmClient.waiters().commandExecuted()
waiter.run(WaiterParameters(GetCommandInvocationRequest()
.withCommandId(commandId)
.withInstanceId(instanceId)
))

aws mobile sdk for unity- How do I get the progress of download from amazon server(using amazon s3)

I am using aws unity sdk for my unity game to download the assets stored in amazon server.I used GetObjectAsync() for download.In the aws sdk for iOS,we get the progress value from NSUrlSessionDelegates.But I want to use aws mobile sdk for unity and get the progress value of download.How do I do this? Please help.
private void GetObject()
{
ResultText.text = string.Format("fetching {0} from bucket {1}",
SampleFileName, S3BucketName);
Client.GetObjectAsync(S3BucketName, SampleFileName, (responseObj) =>
{
string data = null;
var response = responseObj.Response;
if (response.ResponseStream != null)
{
using (StreamReader reader = new StreamReader(response.ResponseStream))
{
data = reader.ReadToEnd();
}
ResultText.text += "\n";
ResultText.text += data;
}
});
}
You can do that. Here is snippet from Amazon develper website.
public event EventHandler<WriteObjectProgressArgs> WriteObjectProgressEvent
TransferUtilityDownloadRequest request = new TransferUtilityDownloadRequest();
request.WriteObjectProgressEvent += displayProgress;
private void displayProgress(object sender, WriteObjectProgressArgs args)
{
Console.WriteLine(args);
}
I have the same problem and I tried to ask on AWS forum.
Unfortunately they doesn't support yet.
Here the link:
https://forums.aws.amazon.com/thread.jspa?threadID=248187&tstart=0
To access of forum is necessary to login.

Grails AWS SDK plugin not resolving PutObjectRequest

I am trying to get my grails app working with Amazon S3, I have been following the following docs... http://agorapulse.github.io/grails-aws-sdk/guide/single.html
At the following step amazonWebService.s3.putObject(new PutObjectRequest('some-grails-bucket', 'somePath/someKey.jpg', new File('/Users/ben/Desktop/photo.jpg')).withCannedAcl(CannedAccessControlList.PublicRead))
The project can't resolve class PutObjectRequest, and I have tried importing com.amazonaws.services.s3.model.PutObjectRequest manually, but it still cant find the class. The only thing I can think of is I might have an older version of the SDK, though I only followed the tutorial.
My BuildConfig.groovy...
...
dependencies{
//dependencies for amazon aws plugin
build 'org.apache.httpcomponents:httpcore:4.3.2'
build 'org.apache.httpcomponents:httpclient:4.3.2'
runtime 'org.apache.httpcomponents:httpcore:4.3.2'
runtime 'org.apache.httpcomponents:httpclient:4.3.2'
}
plugins{
...
runtime ':aws-sdk:1.9.40'
}
has anyone else run into this issue and have a solution?
I don't use the plugin, I simply just use the SDK directly. Not sure what you would need a plugin for. You don't need httpcomponents for it to work
Add this to you dependencies block:
compile('com.amazonaws:aws-java-sdk-s3:1.10.2') {
exclude group: 'com.fasterxml.jackson.core'
}
Heres my bean I use. I set the key, access, and bucket data in the bean configuration
class AmazonStorageService implements FileStorageService {
String accessKeyId
String secretAccessKey
String bucketName
AmazonS3Client s3client
#PostConstruct
private void init() {
s3client = new AmazonS3Client(new BasicAWSCredentials(accessKeyId, secretAccessKey));
}
String upload(String name, InputStream inputStream) {
s3client.putObject(new PutObjectRequest(bucketName, name, inputStream, null).withCannedAcl(CannedAccessControlList.PublicRead));
getUrl(name)
}
String upload(String name, byte[] data) {
upload(name, new ByteArrayInputStream(data))
}
String getUrl(String name) {
s3client.getUrl(bucketName, name)
}
Boolean exists(String name) {
try {
s3client.getObjectMetadata(bucketName, name)
true
} catch(AmazonServiceException e) {
false
}
}
}