Created
March 27, 2013 14:59
-
-
Save chrisa/5254871 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/opt/chef-server/embedded/lib/erlang/bin/escript | |
| -define(SELF, 'me@127.0.0.1'). | |
| -define(ERCHEF, 'erchef@127.0.0.1'). | |
| -define(ERCHEF_COOKIE, 'erchef'). | |
| -define(DEFAULT_KEY_PATH, '/etc/chef-server'). | |
| %% File 00600 mode permission specified the Erlang way. See | |
| %% file:write_file_info for details. | |
| -define(OWNER_RW, 8#00400 + 8#00200). | |
| -define(OSC_ORG_ID, <<"00000000000000000000000000000000">>). | |
| -define(CHEF_SKED_AUTHZ_ID, <<"00000000000000000000000000005ced">>). | |
| -record(chef_user, { | |
| 'id', %% guid for object (unique) | |
| 'authz_id', %% authorization guid (placeholder - not used) | |
| 'username', %% username | |
| 'email', %% email - left null | |
| 'public_key', %% public key - might be null | |
| 'hashed_password', %% password | |
| 'salt', %% password salt | |
| 'hash_type', %% hash used to scramble password | |
| 'last_updated_by', %% authz guid of last actor to update object - | |
| %% it is a place holder in this case | |
| 'created_at', %% time created at | |
| 'updated_at', %% time updated at | |
| 'external_authentication_uid', %% External UID, such as LDAP - nullable | |
| 'recovery_authentication_enabled', %% not used, will be null | |
| 'admin' %% if the user is an admin | |
| }). | |
| main([Op, Name, HashedPassword, Salt, HashType]) -> | |
| init_network(), | |
| case Op of | |
| "create" -> | |
| create_user(Name, HashedPassword, Salt, HashType); | |
| "update" -> | |
| update_user(Name, HashedPassword, Salt, HashType); | |
| _ -> | |
| io:format("first arg must be create or update~n") | |
| end. | |
| init_network() -> | |
| net_kernel:start([?SELF, longnames]), | |
| erlang:set_cookie(node(), ?ERCHEF_COOKIE), | |
| pong = net_adm:ping(?ERCHEF). | |
| create_user(Name, HashedPassword, Salt, HashType) -> | |
| DbContext = make_context(), | |
| Id = make_org_prefix_id(?OSC_ORG_ID, Name), | |
| User = #chef_user{id = Id, | |
| authz_id = Id, | |
| username = Name, | |
| email = "", | |
| hashed_password = HashedPassword, | |
| salt = Salt, | |
| hash_type = HashType, | |
| public_key = "", | |
| external_authentication_uid = null, %% Not used in open source user | |
| recovery_authentication_enabled = false, %% Not used in open source user | |
| admin = true | |
| }, | |
| Args = [User, DbContext, ?CHEF_SKED_AUTHZ_ID], | |
| Result = rpc:call(?ERCHEF, chef_db, create, Args), | |
| process_create_result(Name, Result). | |
| process_create_result(Name, Result) -> | |
| case Result of | |
| ok -> | |
| io:format("user ~p created.~n", [Name]), | |
| {ok, created}; | |
| {conflict, _} -> | |
| io:format("user ~p already exists~n", [Name]), | |
| halt(2); | |
| Error -> | |
| io:format("error creating user ~p: ~p~n", [Name, Error]), | |
| halt(2) | |
| end. | |
| update_user(Name, HashedPassword, Salt, HashType) -> | |
| DbContext = make_context(), | |
| FetchArgs = [DbContext, Name], | |
| User = rpc:call(?ERCHEF, chef_db, fetch_user, FetchArgs), | |
| case User of | |
| not_found -> | |
| io:format("user ~p not found.~n", [Name]); | |
| {error,Error} -> | |
| io:format("error retrieving user ~p: ~p~n", [Name, Error]); | |
| _ -> | |
| UpdatedUser = User#chef_user{hashed_password=HashedPassword, salt=Salt, hash_type=HashType}, | |
| UpdateArgs = [DbContext, UpdatedUser, ?CHEF_SKED_AUTHZ_ID], | |
| Result = rpc:call(?ERCHEF, chef_db, update, UpdateArgs), | |
| process_update_result(Name, Result) | |
| end. | |
| process_update_result(Name, Result) -> | |
| case Result of | |
| ok -> | |
| io:format("user ~p updated.~n", [Name]), | |
| {ok, updated}; | |
| Error -> | |
| io:format("error updating user ~p: ~p~n", [Name, Error]), | |
| halt(2) | |
| end. | |
| %% Get a DB context object | |
| make_context() -> | |
| Args = [make_req_id()], | |
| rpc:call(?ERCHEF, chef_db, make_context, Args). | |
| %% Create a binary string used as the request identifier. | |
| make_req_id() -> | |
| TS = os:timestamp(), | |
| Rand = base64:encode(crypto:rand_bytes(6)), | |
| {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_universal_time(TS), | |
| iolist_to_binary(io_lib:format("~s-~4w-~2..0w-~2..0w-~2..0w:~2..0w:~2..0w-~s", | |
| [?MODULE, | |
| Year, Month, Day, | |
| Hour, Minute, Second, | |
| Rand])). | |
| make_org_prefix_id(OrgId, Name) -> | |
| %% assume couchdb guid where trailing part has uniqueness | |
| <<_:20/binary, OrgSuffix:12/binary>> = OrgId, | |
| Bin = iolist_to_binary([OrgId, Name, crypto:rand_bytes(6)]), | |
| <<ObjectPart:80, _/binary>> = crypto:md5(Bin), | |
| iolist_to_binary(io_lib:format("~s~20.16.0b", [OrgSuffix, ObjectPart])). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment