{"id":19367127,"url":"https://github.com/abailly/nix-haskell-dev-vm","last_synced_at":"2026-05-29T16:31:39.344Z","repository":{"id":66589897,"uuid":"334210131","full_name":"abailly/nix-haskell-dev-vm","owner":"abailly","description":"Terraform-based VM configuration to hack haskell with nix","archived":false,"fork":false,"pushed_at":"2022-02-21T07:40:15.000Z","size":59,"stargazers_count":0,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-24T13:46:23.597Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abailly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-29T17:05:24.000Z","updated_at":"2021-11-18T11:20:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"bb754fe1-d5b2-4f25-91f7-ddbd681d8734","html_url":"https://github.com/abailly/nix-haskell-dev-vm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/abailly/nix-haskell-dev-vm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abailly%2Fnix-haskell-dev-vm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abailly%2Fnix-haskell-dev-vm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abailly%2Fnix-haskell-dev-vm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abailly%2Fnix-haskell-dev-vm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abailly","download_url":"https://codeload.github.com/abailly/nix-haskell-dev-vm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abailly%2Fnix-haskell-dev-vm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33662205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T07:48:18.442Z","updated_at":"2026-05-29T16:31:39.338Z","avatar_url":"https://github.com/abailly.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Development Environment\n\n[Terraform](https://www.hashicorp.com/products/terraform) based code to setup a development environment for hacking Haskell code in general, and\nprojects using IOHK's infrastructure in particular. The VM will be configured to use:\n\n* Vanilla [Emacs]() for editing code, with [lsp-mode](https://emacs-lsp.github.io/) using [lsp-haskell](https://emacs-lsp.github.io/lsp-haskell/) and [haskell-language-server](https://github.com/haskell/haskell-language-server),\n* [nix](https://nixos.org/) for dependencies management and building Haskell code, with nix-shell providing the proper environment for emacs' LSP,\n* [cachix](https://cachix.org/) configuration to speed up build,\n* [direnv](https://direnv.net/) to provide a per-directory environment that will trigger entering nix.\n\n# Install\n\n## GCP\n\nterraform and packer require access to GCP resources which is controlled by a _Service account_ configuration.\n\nAssuming one has \"admin\" access to a GCP project, the following steps will create a service account, set the needed permissions and retriev a key file which can then be used to configure the scripts:\n\nCreate the service account:\n\n```\n$ gcloud iam service-accounts create hydra-poc-builder\n```\n\nAdd needed permissions:\n\n```\n$ gcloud projects add-iam-policy-binding iog-hydra --member \"serviceAccount:hydra-poc-builder@iog-hydra.iam.gserviceaccount.com\" --role \"roles/compute.admin\"\n$ gcloud projects add-iam-policy-binding iog-hydra --member \"serviceAccount:hydra-poc-builder@iog-hydra.iam.gserviceaccount.com\" --role \"roles/iam.serviceAccountUser\"\n$ gcloud projects add-iam-policy-binding iog-hydra --member \"serviceAccount:hydra-poc-builder@iog-hydra.iam.gserviceaccount.com\" --role \"roles/compute.instanceAdmin.v1\"\n$ gcloud projects add-iam-policy-binding iog-hydra --member \"serviceAccount:hydra-poc-builder@iog-hydra.iam.gserviceaccount.com\" --role \"roles/storage.objectAdmin\"\n```\n\nThe service account must be able to create various `compute` instances, to modify the state which is stored inside a _Google Storage_ bucket, and to impersonate a service account user (unsure what this really means...).\n\nCreate service account's key file:\n\n```\n$ gcloud iam service-accounts keys create hydra-poc-builder.json --iam-account hydra-poc-builder@iog-hydra.iam.gserviceaccount.com\n```\n\n## Building the base image\n\nThis is not mandatory and can be changed by editing the `image = iog-hydra-xxxx` parameter in [compute.tf](./compute.tf) but this code also provides [Packer](https://www.packer.io/) script to build a base image:\n\n```\n$ cd packer\n$ packer build build.json -var 'gcp_account_file=xxx' -var 'gcp_project_id=zzz'\n... \u003ctakes some time\u003e\n```\n\nThe [builder](https://www.packer.io/docs/templates/builders) depends on two user variables that tells packer how to authenticate to GCP and which project to run the builder in. This base image will be named `iog-hydra-\u003ctimestamp\u003e` and available for use once the build finishes. The configuration of the image is done using script [build-env.sh](./packer/build-env.sh).\n\n## Deploying the VM\n\nInitialise Terraform:\n\n```\n$ terraform init\n```\n\nCreate a `compute.tfvars` containing a single variable for `cachix_authentication` token. It can be left empty, in which no additional cachix configuration will be done when the VM spins up.\n\nUpdate the `ssh_keys` file with public keys that will be allowed to log into the VM, prefixing each key with `curry` or `root` depending on whether one wants to provide normal user or super-user access to the VM. Note the user `curry` will automatically be given `sudo` rights by the packer builder.\n\nThen create a deployment plan and apply it:\n\n```\n$ terraform plan -out vm.plan  -var-file compute.tfvars\n$ terraform apply vm.plan\n... \u003ctakes some more time\u003e\n\nApply complete! Resources: 2 added, 0 changed, 0 destroyed.\n\nOutputs:\n\ninstance_id = https://www.googleapis.com/compute/v1/projects/xxx\ninstance_ip = X.Y.Z.T\n```\n\n### Snapshots\n\nDeploying a VM from scratch takes a while, depending on the current set of projects configured (see [configure.sh](scripts/configure.sh)). To speed things up there's provision to replace the VM's image-based disk with a snapshot-based disk, and to create snapshots from a running VM.\n\nAssuming VM is running, creating a snapshot is as simple as :\n\n```\n$ scripts/snapshot.sh\n```\n\n\nUsing an existing snapshot requires setting the `use_snapshot` in terraform to `1`:\n\n```\n$ terraform apply -var-file=dev-vm.tfvars -var use_snapshot=1 -auto-approve\n```\n\n# Using the VM\n\nThen one should be able to log into the VM as user `curry`, start tmux and emacs, and then hack some stuff.\n\nTo log in to the VM:\n\n```\n$ scripts/login.sh curry@haskell-dev-vm-1\n```\n\n\n# Troubleshooting\n\nMost issues boil down to authentication or authorisation problems.\n\n\u003e Packer times out while trying to build an image\n\n```\ngooglecompute: output will be in this color.\n\n==\u003e googlecompute: Checking image does not exist...\n==\u003e googlecompute: Creating temporary rsa SSH key for instance...\n==\u003e googlecompute: Using image: ubuntu-2004-focal-v20210112\n==\u003e googlecompute: Creating instance...\n    googlecompute: Loading zone: europe-west4-a\n    googlecompute: Loading machine type: n1-standard-1\n    googlecompute: Requesting instance creation...\n    googlecompute: Waiting for creation operation to complete...\n==\u003e googlecompute: Error creating instance: time out while waiting for instance to create\nBuild 'googlecompute' errored after 5 minutes 6 seconds: Error creating instance: time out while waiting for instance to create\n\n==\u003e Wait completed after 5 minutes 6 seconds\n\n==\u003e Some builds didn't complete successfully and had errors:\n--\u003e googlecompute: Error creating instance: time out while waiting for instance to create\n\n==\u003e Builds finished but no artifacts were created.\n```\n\nThe `build.json` definition uses a service account which is passed through `gcp_account_file` variable. The service account probably is missing some permissions.\n\n\u003e Cannot log in to the VM using `scripts/login.sh`\n\nThis script uses `GOOGLE_APPLICATION_CREDENTIALS` environment variable to activate the corresponding service account and use `gcloud compute ssh` to log in. Check authorizations of the service account.\n\n\u003e Cannot log in to the VM using plain `ssh`\n\n* The set of authorized public keys is defined in the [ssh_keys](./ssh_keys) file: Check there is a private key corresponding to this public key. Changing the `ssh_keys` file and re-running `terraform apply` does not entail recreation of the VM so it's pretty fast\n* If `ssh-agent` is running, check that a private key corresponding to an authorized public key is loaded with `ssh-add -l`\n\n\u003e Terraform fails to run `scripts/configure.sh` on the VM\n\nTerraform relies on plain SSH to connect to the VM, so this can be caused by the same problems as the previous issue\n\n\u003e Pushing or pulling to/from GitHub fails\n\n* When log in to the VM, ensures agent forwarding (`ssh -A ...`) is set and that `ssh-agent` is running. Agent forwarding is enabled by default in the `scripts/login.sh`.\n* The ordering of keys loaded in `ssh-agent` _matters_: Git will try each key in order until it succeeds to access `git@github.com`, and _then_ will try to access the repository. If a key is known to GitHub but does not have access to the repository, then git will fail without given much information. Check the order using `ssh-add -l` and fix it in case of doubts\n\n\u003e Some keyboard combinations for Emacs/Vim/Tmux are not available\n\nThis comes from the terminal and/or OS configuration which might capture certain combinations before sending them to the remote host.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabailly%2Fnix-haskell-dev-vm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabailly%2Fnix-haskell-dev-vm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabailly%2Fnix-haskell-dev-vm/lists"}