Friday, August 26, 2011

How to force EC2 root partition to fill EBS volume completely

At some point I noticed that my new great m1.large EBS backed EC2 instance is not completely utilizing root volume (8GB), it was just 2GB only. I can guess the reason of this problem and it's a long story. In two words -- this instance were created from EBS AMI which is done by converting S3 backed AMI. Anyway here it is: 8GB volume and only 2GB root.

Luckily there is a very simple solution. If your root filesystem is Ext3 or Ext4 (assuming /dev/sda1 device):
resize2fs /dev/sda1
If you use XFS then run following command (didn't try it myself but it have to work):
xfs_growfs /
The same commands are required if you decide to increase your root partition at some point.

Monday, June 20, 2011

iPhone Twitter oAuth

I've faced the problem of interaction with twitter from my iPhone application. oAuth makes life very complicated at first glance. But, actually, oAuth was not the problem. The problem is that all the libraries I tried to use were obsolete or buggy. Some of them have been created for a long time ago and didn't work, some of them are more fresh and show twitter login page but they have a javascript bug (or something like that), which does not allow to handle the login process properly.

The only tool which does work is ShareKit by Nate Weiner.

Of course, it requires some changes to be used just for twitter authorization, etc. Here is the code necessary to get authorized on twitter and get authorized user friends and user profile information.

I have created a new class based on SHKTwitter (see the code below). This is how to use it (somewhere in your controller).

In viewDidLoad:

_twitter = [[FTTwitter alloc] init];
_twitter.ftDelegate = self;


In viewDidAppear:

if ([_twitter isAuthorized]) {
NSString* screenname = [_twitter getAuthValueForKey:@"screen_name"];
[_twitter getFriends:screenname];
} else {
[_twitter promptAuthorization];
}


Delegate methods:

- (void)twitterGotFriends:(NSArray *)ids {
// save friends somewhere
}


The code which avoids extra calling, double calling, etc is skipped, of course.

File FTTwitterDelegate.h:

#import

@protocol FTTwitterDelegate

- (void)twitterGotFriends:(NSArray*)ids;

@end


File FTTwitter.h:

#import
#import "SHKTwitter.h"
#import "FTTwitterDelegate.h"

@interface FTTwitter : SHKTwitter {
id _ftDelegate;
}

@property (nonatomic, assign) id ftDelegate;

- (void)verifyCredentials;
- (void)verifyCredentialsTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data;
- (void)verifyCredentialsTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error;

- (void)getFriends:(NSString*)screenname;
- (void)getFriendsTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data;
- (void)getFriendsTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error;

@end


File FTTwitter.m:

#import "FTTwitter.h"
#import "JSON.h"

@implementation FTTwitter

@synthesize ftDelegate = _ftDelegate;

- (void)verifyCredentials {
OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.twitter.com/1/account/verify_credentials.json"]
consumer:consumer
token:accessToken
realm:nil
signatureProvider:nil];

[oRequest setHTTPMethod:@"GET"];

OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest
delegate:self
didFinishSelector:@selector(verifyCredentialsTicket:didFinishWithData:)
didFailSelector:@selector(verifyCredentialsTicket:didFailWithError:)];

[fetcher start];
[oRequest release];
}

- (void)verifyCredentialsTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
// TODO better error handling here
NSString* json = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
ZZLOG(@"json: %@", json);
NSDictionary* response = [json JSONValue];
[SHK setAuthValue:[response objectForKey:@"screen_name"] forKey:@"screen_name" forSharer:[self sharerId]];

NSString* screen_name = [self getAuthValueForKey:@"screen_name"];

[[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Retrieving friends")];

[self getFriends:screen_name];
}

- (void)verifyCredentialsTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error {
[[SHKActivityIndicator currentIndicator] hide];
ZZLOG(@"can't get user information");
}

- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
[super tokenAccessTicket:ticket didFinishWithData:data];

[[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Retrieving screenname")];
[self verifyCredentials];
}

- (void)getFriends:(NSString*)screenname {
OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.twitter.com/1/friends/ids.json"]
consumer:consumer
token:accessToken
realm:nil
signatureProvider:nil];
[oRequest setHTTPMethod:@"GET"];

OARequestParameter* p = [[OARequestParameter alloc] initWithName:@"screen_name" value:screenname];
[oRequest setParameters:[NSArray arrayWithObject:p]];

OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest
delegate:self
didFinishSelector:@selector(getFriendsTicket:didFinishWithData:)
didFailSelector:@selector(getFriendsTicket:didFailWithError:)];

[fetcher start];
[oRequest release];
}

- (void)getFriendsTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
NSString* json = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSArray* ids = [json JSONValue];

// call delegate here!!!
if ([_ftDelegate respondsToSelector:@selector(twitterGotFriends:)]) {
[_ftDelegate twitterGotFriends:ids];
}

[[SHKActivityIndicator currentIndicator] hide];
}

- (void)getFriendsTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error {
[[SHKActivityIndicator currentIndicator] hide];
}

@end

Wednesday, February 2, 2011

Root login to Amazon EC2 instance

Login to fresh EC2 instance as root can return error: "Please login as the ec2-user user rather than root user". You can login easily as "ec2-user" and execute administration commands using "sudo ..." or just become root using "sudo su". But it's not always comfortable and if you want to login via SSH as root, follow these simple steps.
  1. Edit the /etc/ssh/sshd_config file and change the line that says "PermitRootLogin No" to "PermitRootLogin without-password". Then restart the sshd server with "service sshd restart". Be careful, if you screw up the sshd file, it is possible you will only have your current ssh session to fix it, so always test any changes with a second session.
  2. Edit the /root/.ssh/authorized_keys file. The first (and only) entry starts with "command ... sleep 10; ssh-rsa [big long key]". If you remove the text from the beginning of the line until where it says "ssh-rsa", you will be able to login as root via SSH with your Amazon keypair.

Tuesday, February 1, 2011

Bzr to Git Migration

The migration from Bzr to Git is very simple, though it's not obvious. We found that Git is faster on pushing to (and pulling from) remote repositories. This is the only reason why we migrate some projects from Brz to Git. As for any other aspects — we are just happy with Bzr.

Well, I suppose you work on Linux.

1. Install bzr fastimport plugin:
> mkdir -p ~/.bazaar/plugins
> cd ~/.bazaar/plugins
> bzr clone lp:bzr-fastimport fastimport
2. Install python package required by fastimport plugin:
> cd ~
> bzr clone lp:python-fastimport
> cd python-fastimport
> ./setup.py install (need root privileges here)
3. Now we can export bzr repository to git:
> cd my-bzr-repos
> git init
> bzr fast-export --plain . | git fast-import
> rm -rf .bzr
> git reset --hard
Here it is.

Saturday, January 29, 2011

Generate random password in Linux

Sometimes you need to set random password for some user or service. And it's not always easy to take random combination from the head. Use this simple command to automate thinking process:

echo `</dev/urandom tr -dc A-Za-z0-9 | head -c8`

Obviously, this can be tweaked to your liking by adding symbols to the list of allowed characters and changing the length of the generated password in the head options.

Sunday, September 5, 2010

How to hide iPhone keyboard with Done button

iPhone keyboard is nice useful control but there is possibility to hide it once you finished edit. For simple text keyboard you can catch click on "return" button and hide it, but there is no such button on numeric keyboard.

The solution is "Done" button on the navigation bar. It need to be shown once keyboard appear.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] 
    initWithBarButtonSystemItem:UIBarButtonSystemItemDone 
    target:self action:@selector(turnOffEditing)];

Next implement turnOffEditing method, it need to hide keyboard and remove our button.
- (void)turnOffEditing {
    [self.view endEditing:YES];
    self.navigationItem.rightBarButtonItem = nil;
}
Keyboard is hidden by nice endEditing call. It fetch all input fields from your view and hide keyboard by sending resignFirstResponder.

Wednesday, June 16, 2010

Customizing TTTableMessageItem

I hope you already know about iPhone framework Three20. Sometimes you have to change a table cell for your special needs. This post describes how to manage it.

Let's suppose you have to take out timestamp label from TTTableMessageItemCell. I'll describe process step by step.

1. Inherit TTTableMessageItemCell and create your own class, say FruitItemCell. And rewrite method setObject:


@implementation FruitItemCell

- (void)setObject:(id)object {
[super setObject:object];
self.timestampLabel.hidden = YES;
self.timestampLabel.text = @"";
}

Looks great isn't it? But it is not time to fun. Because now you have to make the framework to involve your new awesome class into process. The next step is about it.

2. Create correct table cells in your datasource:

@implementation FruitDataSource
...
- (Class)tableView:(UITableView*)tableView cellClassForObject:(id)object {
if ([object isKindOfClass:[TTTableMessageItem class]]) {
return [FruitItemCell class];
}
return [super tableView:tableView cellClassForObject:object];
}

Now the framework will create correct cell instances for your data items.