Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.0.0

- Rename `LoginGov` namespace back to `Identity` (big breaking change)

# 0.4.3

- Added `LoginGov::Hostdata.config`
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# LoginGov::Hostdata (`identity-hostdata`)
# Identity::Hostdata (`identity-hostdata`)

A gem to help read configuration from login.gov infrastructure, according to the [login.gov infrastructure contract][contract].

Expand All @@ -17,7 +17,7 @@ Use this gem to access config data on a per-host basis. The config data is read
```ruby
require 'identity/hostdata'

LoginGov::Hostdata.domain
Identity::Hostdata.domain
# => "login.gov"
```

Expand All @@ -26,7 +26,7 @@ Download configs from S3:
```ruby
root = File.expand_path('../../', __FILE__)

LoginGov::Hostdata.in_datacenter do |hostdata|
Identity::Hostdata.in_datacenter do |hostdata|
hostdata.s3.download_configs(
'/%{env}/v1/idp/database.yml' => File.join(root, 'config/database_s3.yml')
)
Expand Down
16 changes: 8 additions & 8 deletions docs/contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

## `/etc/login.gov`

The `/etc/login.gov` directory will exist on deployed instanes of login.gov apps. It contains individual files with useful data, and can be accessed through `LoginGov::Hostdata` class methods
The `/etc/login.gov` directory will exist on deployed instanes of login.gov apps. It contains individual files with useful data, and can be accessed through `Identity::Hostdata` class methods

| File | API | Example |
| ---- | --- | ------- |
| `/etc/login.gov/info/env` | `LoginGov::Hostdata.env` | `"int"` |
| `/etc/login.gov/info/domain` | `LoginGov::Hostdata.domain` | `"login.gov"` |
| `/etc/login.gov/info/env` | `Identity::Hostdata.env` | `"int"` |
| `/etc/login.gov/info/domain` | `Identity::Hostdata.domain` | `"login.gov"` |

## EC2 instance metadata

Expand All @@ -16,11 +16,11 @@ We use [instance metadata][instance-metadata] (an HTTP request from an EC2 box)
- region
- account ID

The [LoginGov::Hostdata::EC2](../lib/login_gov/hostdata/ec2.rb) class helps load and read this data:
The [Identity::Hostdata::EC2](../lib/identity/hostdata/ec2.rb) class helps load and read this data:

```ruby
ec2_data = LoginGov::Hostdata::EC2.load
# => #<LoginGov::Hostdata::EC2:0x00007fc49dd30f40 ...>
ec2_data = Identity::Hostdata::EC2.load
# => #<Identity::Hostdata::EC2:0x00007fc49dd30f40 ...>
ec2_data.region
# => "us-west-1"
ec2_data.account_id
Expand All @@ -39,10 +39,10 @@ The bucket names can correspond to account IDs and regions:
"login-gov.app-secrets.#{ec2.account_id}-#{ec2.region}"
```

The [LoginGov::Hostdata::S3](../lib/login_gov/hostdata/s3.rb) class helps manage access to data in these buckets, and the `LoginGov::Hostdata.s3` convenience method helps build S3 instances and download remote config files locally:
The [Identity::Hostdata::S3](../lib/identity/hostdata/s3.rb) class helps manage access to data in these buckets, and the `Identity::Hostdata.s3` convenience method helps build S3 instances and download remote config files locally:

```ruby
s3 = LoginGov::Hostdata.s3
s3 = Identity::Hostdata.s3
# downloads the `foobar.yml` file for the current environment to local path `config/foobar.yml`
s3.download_configs(
'%{env}/idp/v1/foobar.yml' => 'config/foobar.yml'
Expand Down
4 changes: 2 additions & 2 deletions identity-hostdata.gemspec
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# coding: utf-8
lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "login_gov/hostdata/version"
require "identity/hostdata/version"

Gem::Specification.new do |spec|
spec.name = "identity-hostdata"
spec.version = LoginGov::Hostdata::VERSION
spec.version = Identity::Hostdata::VERSION
spec.authors = ["Zach Margolis"]
spec.email = ["identity-devops@login.gov"]

Expand Down
100 changes: 99 additions & 1 deletion lib/identity/hostdata.rb
Original file line number Diff line number Diff line change
@@ -1 +1,99 @@
require "login_gov/hostdata"
require "identity/hostdata/ec2"
require "identity/hostdata/s3"
require "identity/hostdata/version"
require "json"

module Identity
module Hostdata
class MissingConfigError < StandardError; end

CONFIG_DIR = '/etc/login.gov'
DOMAIN_PATH = File.join(CONFIG_DIR, 'info/domain')
ENV_PATH = File.join(CONFIG_DIR, 'info/env')
INSTANCE_ROLE_PATH = File.join(CONFIG_DIR, 'info/role')

def self.domain
@domain ||= begin
File.read(DOMAIN_PATH).chomp
rescue Errno::ENOENT => err
raise MissingConfigError, err.message if in_datacenter?
end
end

def self.env
@env ||= begin
File.read(ENV_PATH).chomp
rescue Errno::ENOENT => err
raise MissingConfigError, err.message if in_datacenter?
end
end

# @return [Hash] parses the environment's config JSON
def self.config
@config ||= begin
config_path = File.join(
CONFIG_DIR,
'repos/identity-devops/kitchen/environments',
"#{env}.json"
)

JSON.parse(File.read(config_path), symbolize_names: true)
rescue Errno::ENOENT => err
raise MissingConfigError, err.message if in_datacenter?
{}
end
end

def self.instance_role
@instance_role ||= begin
File.read(INSTANCE_ROLE_PATH).chomp
rescue Errno::ENOENT => err
raise MissingConfigError, err.message if in_datacenter?
end
end

def self.in_datacenter?
return @in_datacenter if defined?(@in_datacenter)
@in_datacenter = File.directory?(CONFIG_DIR)
end

# @yield Executes a block if in_datacenter?
# @yieldparam hostdata
def self.in_datacenter
raise LocalJumpError, 'in_datacenter must be called with a block' unless block_given?
yield self if in_datacenter?
end

# @return [S3]
def self.s3(logger: default_logger, s3_client: nil)
ec2 = Identity::Hostdata::EC2.load

Identity::Hostdata::S3.new(
env: env,
region: ec2.region,
logger: logger,
s3_client: s3_client,
bucket: "login-gov.app-secrets.#{ec2.account_id}-#{ec2.region}"
)
end

# @return [Logger]
def self.logger
@logger ||= Logger.new(STDOUT)
end

class << self
alias_method :default_logger, :logger

attr_writer :logger
end

# @api private
# Used to clear memoized values (intended for specs)
def self.reset!
instance_variables.each do |variable|
remove_instance_variable(variable)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'net/http'

module LoginGov
module Identity
module Hostdata
# Class to wrap accessing the EC2 metadata service
class EC2
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module LoginGov
module Identity
module Hostdata
# In-memory imitation of Aws::S3::Client for use in tests
# Not required by default, use `require 'login_gov/hostdata/fake_s3_client'`
# Not required by default, use `require 'identity/hostdata/fake_s3_client'`
class FakeS3Client
def get_object(bucket:, key:, response_target:)
File.open(response_target, 'wb') do |file|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
require 'json'
require 'logger'

module LoginGov
module Identity
module Hostdata
class S3
attr_reader :bucket, :env, :region, :logger
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module LoginGov
module Identity
module Hostdata
VERSION = '0.4.3'
end
Expand Down
99 changes: 0 additions & 99 deletions lib/login_gov/hostdata.rb

This file was deleted.

6 changes: 3 additions & 3 deletions spec/login_gov/hostdata/ec2_spec.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require 'spec_helper'

RSpec.describe LoginGov::Hostdata::EC2 do
RSpec.describe Identity::Hostdata::EC2 do
describe '.load' do
subject(:load) { LoginGov::Hostdata::EC2.load }
subject(:load) { Identity::Hostdata::EC2.load }

it 'loads data from the magic ECS URL' do
stub_request(:get, 'http://169.254.169.254/2016-09-02/dynamic/instance-identity/document').
Expand Down Expand Up @@ -39,7 +39,7 @@
}
end

subject(:ec2) { LoginGov::Hostdata::EC2.new(document) }
subject(:ec2) { Identity::Hostdata::EC2.new(document) }

describe '#region' do
subject(:region) { ec2.region }
Expand Down
10 changes: 5 additions & 5 deletions spec/login_gov/hostdata/s3_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
require 'spec_helper'

RSpec.describe LoginGov::Hostdata::S3 do
let(:fake_s3) { LoginGov::Hostdata::FakeS3Client.new }
RSpec.describe Identity::Hostdata::S3 do
let(:fake_s3) { Identity::Hostdata::FakeS3Client.new }

around(:each) do |ex|
LoginGov::Hostdata.reset!
Identity::Hostdata.reset!

@logger = Logger.new('/dev/null') # set up before FakeFS

Expand All @@ -18,7 +18,7 @@
let(:region) { 'us-west-2' }
let(:logger) { @logger }
subject(:s3) do
LoginGov::Hostdata::S3.new(
Identity::Hostdata::S3.new(
bucket: bucket,
env: env,
region: region,
Expand Down Expand Up @@ -64,7 +64,7 @@

it 'logs which files its downloading' do
expect(logger).to receive(:info).with(
"LoginGov::Hostdata::S3: downloading s3://some-bucket-name/staging/v1/idp/some_config.yml to #{local_config_file}"
"Identity::Hostdata::S3: downloading s3://some-bucket-name/staging/v1/idp/some_config.yml to #{local_config_file}"
)

download_configs
Expand Down
Loading