One place for hosting & domains

      Create

      How to Create a Brand Style Guide for Your Website


      Maintaining consistency is vital to a brand’s success. However, if you have several people involved in creating and maintaining your website, and they aren’t on the same page when it comes to how to portray your brand, consistency becomes difficult to achieve.

      A style guide can provide your team with the tools to better maintain your brand’s image, and give your site’s users a dependable experience. In other words, by establishing clearer and more efficient communication across your team, style guides improve the experience of your brand for both the people creating it and those encountering it.

      In this article, we’ll discuss what a brand style guide is and why it’s essential to your website. Then we’ll explain how to create one for your site in just five steps. Let’s get going!

      An Introduction to Brand Style Guides

      A brand style guide is a set of rules for how your brand will be portrayed, both online and off. Think of it as the foundation of your brand story. This includes its web design, tone, and content, the way you handle customer interactions, and more. Businesses are built on customers’ perceptions, so anything that impacts how your site’s audience sees your brand can be taken into account.

      Some specific areas of interest for your style guide might include visual design elements and choices such as color scheme, iconography and typography, site layout, images, and logos (including your marketing materials). Your web copy, ‘about’ page, blog, and social media content should also match your brand personality in the eyes of users.

      Any elements related to user interactions, including live chats and forms, also make an impact on how customers feel about your brand. How quickly you respond, what you say, and how you say it can turn a lead into a promoter for your brand. When done poorly, it can also lead them towards your competition instead.

      It’s important to note that a style guide, or brand book, is different from a pattern library. While pattern libraries are also useful, they only list the essential elements of your brand’s visual identity. They don’t provide any direction as to how those elements should be used. For example, without a style guide, your team may have a copy of your logo at hand, but they won’t know what to do with it.

      Why a Brand Style Guide Is Crucial to Your Website

      Having a brand style guide for your website keeps all team members on the same page about how to present your content to the world. It’s also helpful if you have to hire outside designers or developers to work on your site, as it can prevent them from taking off with their own ideas and leaving your site looking disjointed.

      Consistency is key to a brand’s success. Users will more quickly recognize your brand if you have a distinct style that you use everywhere. What’s more, if all aspects of your brand’s identity aren’t the same across your website, social media platforms, and anywhere else it appears, users may become confused and wonder if it’s all really part of the same brand.

      Implementing a thorough brand style guide as soon as you bring in new team members (or even freelancers, such as graphic designer or web developer) will set the standard for consistency right out of the gate. The more consistent you can be, the faster you’ll be able to start building your brand identity and acquiring repeat users.

      Shared Hosting That Powers Your Purpose

      We make sure your website is fast, secure and always up so your visitors trust you. Plans start at $2.59/mo.

      How to Create a Brand Style Guide for Your Website (5 Key Steps)

      There are several factors to consider when creating your brand style guide. Most importantly, building it around your vision for your brand will enable you to craft brand guidelines that help you achieve your goals. Let’s talk about how that process works.

      Step 1: Decide Where Your Style Guide Will ‘Live’

      Style guides can be created in a variety of formats. Where your guidelines will reside is up to you, but remember that a style guide is most useful when it clearly communicates your requirements and is easily accessible to anyone who needs to use it.

      The Netflix brand style guide.

      Some businesses create subdomains for their websites that specify page layout, image and logo placement, font, and more. The advantage of using a subdomain is that it’s a visual representation of your style, instead of just a bulleted list of rules. Anyone using your guide will see precisely what the content they’re creating should look like.

      Alternatively, project management tools such as Trello are also a useful option. They’re made to be used by teams, so it’s easy to share your guide with anyone who might need it. This kind of tool also makes it simple to organize information in a way that provides clear direction to the people working on your brand.

      Of course, if you just need a quick and painless way to create a branding style guide, there’s nothing wrong with writing it up as a document. Including images with examples can help to clarify any complex points. Just make sure the file is easy to share, as you’ll have to make it accessible to everyone who creates content related to your brand.

      Step 2: Clarify Your Brand’s Mission

      You may have an idea of what you want to accomplish with your website, but writing out a clear and firmly-established mission statement is still important. It will be a useful reminder for yourself, and make it easier to communicate your goals to other people working on your brand.

      The mission statement from the “I Heart NY” brand style guide.

      When creating your mission statement, make sure to focus on your brand’s purpose, and be specific about your values and what you hope to accomplish. You’ll want to communicate your big-picture goals, while also providing concrete examples that are easy for people to remember.

      Step 3: Define Your Brand’s Tone and Voice

      Your brand’s ‘tone’ is the overall feeling it conveys to your target audience, while its ‘voice’ is its specific personality. Tone can be easily communicated through images and written content. Voice will also come across in written content, and in interactions with users.

      Tone of voice guidelines from the Urban Outfitters brand style guide.

      Your brand’s tone and voice often define how users interact with your content, and what emotions it evokes in them. Using the same style consistently helps users get to know your business ‘personally.’ Just as a person who is joking around one minute and angry the next can be off-putting, sudden shifts in tone and voice will likely confuse your users.

      Incorporating tone and voice into your style guide can be tricky. However, you can start by listing qualities you want your content to express, and emotions you’d like it to trigger. It’s also smart to use your brand’s tone and voice to create the guide itself. If you’re going for a relaxed and welcoming vibe, for example, throw in a few emojis or some slang. On the other hand, more formal brands will want to present their guidelines in a straightforward manner.

      Step 4: Determine Guidelines for Your Brand’s Visual Elements

      In your style guide, you’ll also want to include specifications on your logo’s usage. This includes when and where it will be displayed. If you always want your logo to be set as the thumbnail for blog posts, for example, you would want to mention this in your style guide (so everyone who works on blog content will know what to do).

      Spotify’s logo and icon usage guidelines.

      Similarly, setting rules about what kinds of images will be allowed can help you maintain brand consistency across your site. For example, you may want to specify whether memes are appropriate for use in blog posts, or if they’re too casual for your brand’s tone. Mentioning licensing requirements in order to avoid copyright infringement would also be wise.

      Creating a clear list of all the brand colors, typefaces, icons, and layouts you want to use for your site will ensure that the people working on your brand know these specifications exist. It will prevent them from imposing their own preferences and help those with good intentions avoid mistakes, such as using a color palette that’s just a few shades off from your logo.

      Step 5: Allow Your Style Guide to Evolve With Your Brand

      As your brand grows and changes, your style guide will probably need to do the same. Feedback from users, changes in industry standards, and modifications to your mission statement might mean you’ll want to modify your tone or certain visual elements.

      How DreamHost’s logo has changed throughout the years.

      It’s far more effective to let your style adapt with your brand than to cling to your old guidelines and end up with a style that doesn’t match your current goals. Remember, users’ perceptions can make or break your brand. If they find your style confusing or inconsistent with your brand’s message, they’re more likely to have a negative reaction (or to simply not remember you).

      Any time you make updates to your brand bible, be sure to alert everyone working on your site right away. People get used to doing things a certain way, so they may overlook your changes if they aren’t pointed out directly.

      Branding Matters

      Inconsistency across a website’s brand often leads to confusion for your users and your team members. Creating a style guide can help everyone working on your site understand exactly what it should look, sound, and feel like, so your visitors can have a positive experience.

      Do you have any questions about using or creating this type of style guide? Follow us on Twitter and let’s discuss!

      Image credits: Netflix, I Heart NY, Urban Outfitters, Spotify, DreamHost.





      Source link

      How To Create an OAuth App with the Linode Python API Library


      Updated by Linode

      Contributed by

      Linode

      Linode supports the OAuth 2 authorization protocol. OAuth 2 allows a user to safely grant a third-party app permission to act on their behalf. This means that a user could authorize an app to access data and / or make changes to their Linode account and services that are exposed by the Linode APIv4. For example, an app could create or destroy Linodes, manage a NodeBalancer, or alter a domain.

      This guide will show you how to create a simple OAuth application using Flask and the Linode Python API library. This app allows a user to log in with their Linode account and create a Linode with a StackScript. The complete code for this example is available in the Linode APIv4 Python library example repository.

      Before You Begin

      1. Normally, in order to create an OAuth app with Linode your server must have HTTPS enabled. The only exceptions to this rule are localhost addresses, which can use HTTP. As this guide is just a primer and is not intended to supply production ready code, we will be working with a local workstation, using localhost. If you choose to create an app for production, you will need to generate SSL certificates for HTTPS access.

      2. Ensure that Python 3 is installed on your workstation.

      Obtaining a Client ID and a Client Secret

      In order for Linode to verify the identity of your app, called a client, you will need to generate a set of credentials, specifically a client ID and a client secret.

      1. Log in to the Linode Cloud Manager and navigate to your Account Profile.

        OAuth Account Profile

      2. From there, click on the My Apps tab and select Create My App. You will be prompted to supply a label for your app and a callback URL. We will discuss the role of the callback URL in depth later in this guide. For now you can supply the following URL:

        http://localhost:5000/auth_callback
        

        Leave Public unchecked and click Submit.

        OAuth Account Profile

      3. A window will appear with your client secret. Copy this down somewhere secure, as once you exit this window you will not be able to retrieve the client secret again, and will be forced to generate a new one.

        OAuth Account Profile

      4. Once you exit the client secret window your app will appear as part of a list of apps. Note your client ID, as this is the last piece of information you will need to verify your app’s identity.

        OAuth Account Profile

      In summary, you should have these three bits of information, with values similar to the ones provided here:

      OAuth 2 Authentication Exchange

      The OAuth 2 workflow is a series of exchanges between your third-party app and Linode. Below is an explanation of these exchanges.

      1. The end user visits your client application’s website and attempts to login.
      2. Your client application redirects the end user to the authentication server (https://login.linode.com) with your client application’s client ID and requested OAuth scopes, which appear in the URL of the login page.
      3. The end user inputs their username and password to the authorization server and authorizes the login.
      4. The authorization server redirects the end user back to your client application with a temporary authorization code (sometimes called an exchange code) in the URL.
      5. The client application issues a POST request to the authentication server containing the authorization code and the client application’s client secret.
      6. The authentication server responds to the client application with a newly issued OAuth access token.

      In the following sections you will write the code to perform each one of these steps, using the Linode Python API library.

      Setup Your Development Environment

      1. Create a project folder and move into that folder.

        mkdir ~/linode-oauth-project && cd ~/linode-oauth-project
        
      2. For this project, you will need to use pip to download and install the required Python libraries. Install pip if you do not already have it:

        apt install python-pip
        
      3. Install the required Python libraries:

        pip install flask flask-session linode_api4
        

      Configure Your App

      In a text editor, create a file named config.py. Add the following variables and values, being sure to change the values to your own.

      The StackScript used in this example is for demo purposes. To explore other available StackScripts, visit the Linode StackScript Library. Note that the stackscript_id does not have quotation marks around it. The secret key is used for serializing session data, and should be a value only you know.

      config.py
      1
      2
      3
      4
      5
      
      client_id = 'ce571a8cdad1ba4a0a7d'
      client_secret = 'fab8e2222e83b9b2f50a76012122ec20a5acb005ed088f3fccda2c9c2c4e1cbd'
      stackscript_id = 320826
      application_name = 'my-application-name'
      secret_key = 'my-secret-key'

      Author an OAuth2 App

      In this section, you will write the code for the app.

      Include Imports

      Ensure you are in the linode-oauth-project directory and create and open a file called app.py in the text editor of your choice. Include the following libraries:

      app.py
      1
      2
      3
      4
      5
      6
      
      import re
      from flask import Flask, redirect, request, render_template, session, send_from_directory
      from flask_session import Session
      from linode_api4 import (LinodeClient, LinodeLoginClient, StackScript, Image, Region, Type, OAuthScopes)
      
      import config

      Set Up Flask and Session Key

      Copy in the following code to set up Flask and the session secret key:

      app.py
      1
      2
      3
      4
      
      ...
      
      app=Flask(__name__)
      app.config['SECRET_KEY'] = config.secret_key

      Create a Function to Return the Linode Login Client

      In app.py add the following function to return the LinodeLoginClient class. The LinodeLoginClient class is the library’s OAuth interface. Note that we are passing the client_id and client_secret parameters from our config.py file to the class:

      ~/linode-oauth-project/app.py
      1
      2
      3
      4
      
      ...
      
      def get_login_client():
          return LinodeLoginClient(config.client_id, config.client_secret)

      Create an Index Route

      In Flask you can create HTTP endpoints with routes. The index route, defined in the code below at the document root /, will be the route the user will see when they navigate to http://localhost:5000/. This route will be responsible for displaying the available Linode plan types, the available regions, and the StackScript-compatible images that a user will choose from when creating their new Linode.

      To query a list of available plan types and regions you can use the LinodeClient class, which is an interface for Linode’s APIv4. Viewing the Linode plan types and regions does not require any sort of authorization, so you can provide a dummy value of no-token to instantiate the class:

      ~/linode-oauth-project/app.py
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      
      ...
      
      @app.route('/')
      def index():
          client = LinodeClient('no-token')
          types = client.linode.types(Type.label.contains("Linode"))
          regions = client.regions()
          stackscript = StackScript(client, config.stackscript_id)
          return render_template('configure.html',
              types=types,
              regions=regions,
              application_name=config.application_name,
              stackscript=stackscript
          )

      It is important to note that the two API queries in the above code are slightly different from one another. The client.regions method is a top-level method, just as it appears in the Linode API. The client.linode.types method, on the other hand, is part of the Linode group, which is a collection of methods that deal with Linodes. Again, this is because Linode endpoints are grouped that way in the API. Some methods in the Linode Python library are top level, such as domain_create, while others, like networking.ip_assign, are part of a group. For more information on the top-level methods and groupings, consult the library documentation.

      In addition to querying the API, the above route also renders the configure.html template by passing it the types, regions, application name, and StackScript object. The StackScript object contains a list of StackScript compatible images. We will cover templating in a later section.

      Create a Login Route

      Next, create a login route in app.py. This route will perform two functions. First, it will serialize the user’s plan type, region, and image selections into the session.

      Second, this route will redirect the user to Linode’s login page where they will be prompted to authorize your client app and the scopes you have requested for it. Scopes are sets of permissions that define the access level of your client app. For instance, to create a Linode, your end user must authorize the OAuthScopes.Linodes.create scope.

      ~/linode-oauth-project/app.py
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      ...
      
      @app.route('/', methods=["POST"])
      def start_auth():
          login_client = get_login_client()
          session['dc'] = request.form['region']
          session['distro'] = request.form['distribution']
          session['type'] = request.form['type']
          return redirect(login_client.generate_login_url(scopes=OAuthScopes.Linodes.create))

      When the user returns to your app from the Linode login page, they will be directed to the callback URL.

      Note

      Below is a list of available scopes:

      • OAuthScopes.Linodes
      • OAuthScopes.Domains
      • OAuthScopes.StackScripts
      • OAuthScopes.Users
      • OAuthScopes.NodeBalancers
      • OAuthScopes.Tokens
      • OAuthScopes.IPs
      • OAuthScopes.Tickets
      • OAuthScopes.Clients
      • OAuthScopes.Account
      • OAuthScopes.Events
      • OAuthScopes.Volumes

      Each scope is broken into five permissions: view, create, modify, delete, and all. The all permission encompasses the other four permissions.

      Manage the OAuth 2 Callback URL

      The OAuth 2 callback URL has two main responsibilities. Its first responsibility is to help prove the identity of the client application. When a user attempts to log in to Linode through OAuth, instead of redirecting the user back to the page they came from, Linode’s OAuth implementation matches the client ID to the callback URL you have registered with your app on Linode’s system. This ensures that a nefarious third party can’t just steal the client ID, which is public, and attempt to authorize their own app with it.

      The callback URL’s second responsibility is to kick off the process of exchanging an authorization code for an access token. This second process is done over POST, and so it doesn’t require the user to physically leave the page they are returned to after they log in to Linode. Now you will write the code that satisfies this second responsibility.

      In app.py, add the following lines:

      ~/linode-oauth-project/app.py
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      ...
      
      @app.route('/auth_callback')
      def auth_callback():
          code = request.args.get('code')
          login_client = get_login_client()
          token, scopes, _, _ = login_client.finish_oauth(code)
      
          # ensure we have sufficient scopes
          if not OAuthScopes.Linodes.create in scopes:
              return render_template('error.html', error='Insufficient scopes granted to deploy {}'
                      .format(config.application_name))
      
          (linode, password) = make_instance(token, session['type'], session['dc'], session['distro'])
      
          get_login_client().expire_token(token)
          return render_template('success.html',
              password=password,
              linode=linode,
              application_name=config.application_name
          )

      Let’s take a look at what each of the parts of this section does.

      First, a route is defined for the callback with @app.route(), then a function called auth_callback is defined that will run whenever this route is accessed:

      ~/linode-oauth-project/app.py
      1
      2
      3
      4
      
      ...
      @app.route('/auth_callback')
      def auth_callback():
      ...

      When the user is returned to the callback URL, an authorization code is appended to the URL. The variable code is set to retrieve this value from the URL’s request arguments:

      ~/linode-oauth-project/app.py
      1
      2
      3
      
      ...
          code = request.args.get('code')
      ...

      Then you retrieve an instance of the LinodeLoginClient class:

      ~/linode-oauth-project/app.py
      1
      2
      3
      
      ...
          login_client = get_login_client()
      ...

      Once you have the LinodeLoginClient class, you can pass the authorization code to the finish_oauth method, which is a helper method that will manage the authorization code to OAuth token exchange. This method returns an OAuth token, and the scopes the user has agreed upon.

      ~/linode-oauth-project/app.py
      1
      2
      3
      
      ...
          token, scopes, _, _ = login_client.finish_oauth(code)
      ...

      The next section compares the scopes your app requested from the user to the scopes returned by Linode’s OAuth login page. If the returned scopes do not include the correct scopes, in this case the OAuthScopes.Linode.create scope, then an error template is rendered and an error message is displayed:

      ~/linode-oauth-project/app.py
      1
      2
      3
      4
      5
      6
      
      ...
          # ensure we have sufficient scopes
          if not OAuthScopes.Linodes.create in scopes:
              return render_template('error.html', error='Insufficient scopes granted to deploy {}'
                      .format(config.application_name))
      ...

      Once your app has determined that it has the correct permissions, it creates the Linode using the Linode plan type, the region, and the image that the app serialized into session storage. You will create the make_instance function in the next step. The make_instance function returns the linode object, which contains the Linode’s label, group, and IP address, and the function also returns a randomly generated password:

      ~/linode-oauth-project/app.py
      1
      2
      3
      
      ...
          (linode, password) = make_instance(token, session['type'], session['dc'], session['distro'])
      ...

      Once the Linode has been created, the app expires the OAuth access token. Expiring tokens after use is a strong security measure but if your app is performing many actions on behalf of the user, you might find that time-based expiration scheme is more suitable to your needs. The app then renders the success template by passing it the linode object, the password, and application name:

      ~/linode-oauth-project/app.py
      1
      2
      3
      4
      5
      6
      7
      
      ...
          get_login_client().expire_token(token)
          return render_template('success.html',
              password=password,
              linode=linode,
              application_name=config.application_name
          )

      Create a Function to Deploy a Linode

      Now, create the make_instance function that you referenced above:

      ~/linode-oauth-project/app.py
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      ...
      
      def make_instance(token, type_id, region_id, distribution_id):
          client = LinodeClient('{}'.format(token))
          stackscript = StackScript(client, config.stackscript_id)
          (linode, password) = client.linode.instance_create(type_id, region_id,
                  group=config.application_name,
                  image=distribution_id, stackscript=stackscript.id)
      
          if not linode:
              raise RuntimeError("it didn't work")
          return linode, password

      The make_instance function takes an OAuth access token, the type ID, the region ID, and the image (Linux distribution) ID as parameters. It creates an instance of the LinodeClient class, and unlike the instance of LinodeClient used earlier in the guide, this one requires an OAuth token because you will be using it to create a Linode. The function then creates a Linode using the linode.instance_create method, returning the linode object and the password.

      Finally, if there was an error with the creation of the Linode, the if not linode statement will raise a runtime error.

      Set the name Variable

      At the end of your app.py, paste in the following code to make sure you can run your app:

      ~/linode-oauth-project/app.py
      1
      2
      3
      
      if __name__ == '__main__':
          app.debug=True
          app.run()

      Create App Templates

      Now that you have written the backend code for your app, you’ll need to create a frontend user interface. Begin by creating a templates directory in your project directory and moving into it:

      mkdir ~/linode-oauth-project/templates && cd ~/linode-oauth-project/templates
      

      Using your preferred text editor, create and open base.html. This will be the base template from which your other templates will inherit their stylesheets and JavaScript files:

      ~/linode-oauth-project/templates/base.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      
      <html>
      <head>
          <title>Install On Linode</title>
          <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
              integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
          <style>
              body{
                  text-align: center;
                  background-color: #333333;
              }
              .form-group{
                  display: inline-block;
                  text-align: left;
                  width: 250px;
                  border: 1px solid #cccccc;
                  margin: 5px;
                  padding: 5px;
              }
              .form-group label{
                  color: #337ab7;
              }
              .form-group select{
                  font-size: 16px;
                  outline: none;
                  border: 0px solid #000000;
                  box-shadow: inset 0 1px 1px rgba(0,0,0,0);
                  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0);
              }
              .form-group select:focus{
                  box-shadow: inset 0 1px 1px rgba(0,0,0,0);
                  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0);
              }
              .btn-lg{
                  border-radius: 0px;
                  margin-top: 20px;
              }
              .row{
                  margin-bottom: 20px
              }
              .pop{
                  color: #337ab7;
                  font-weight: bold
              }
              code{
                  color: #337ab7;
                  background-color: #eeeeee
              }
              .boxy{
                  border: 1px solid #cccccc;
                  width: 400px;
                  background-color: #f9f9f9;
                  margin: auto;
                  padding: 10px;
              }
          </style>
      </head>
      <body>
          <div class='container' style='background-color: white; border-left: grey; border-right: grey; height: 100%; padding: 20px;'>
              {% block content %}
              {% endblock %}
          </div>
      
          <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
          <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
              integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
              crossorigin="anonymous"></script>
      </body>

      The important thing to note in the above template is the Jinja2 templating tags. They are:

      {% block content %}
      {% endblock %}
      

      As you will see, any template that extends the base.html template and includes code between the opening and closing content block, will render the code laid out by base.html.

      Create a file called configure.html, which will be the UI a user will see when they reach the document root endpoint (/). Copy in the following code:

      templates/configure.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      
      {% extends 'base.html' %}
      {% block content %}
          <form method="POST">
              <div class='row'>
                  <h1>Deploy <span style="color: #337ab7;">{{application_name}}</span> to a Linode</h1>
                  <p>
                      This will create a brand new Linode running {{application_name}} on your
                      account and give you the credentials.
                  </p>
              </div>
              <div class='row'>
                  <div class='form-group'>
                      <label for='type'>Type</label>
                      <select name='type'i id='type' class='form-control'
                          onblur="blurring(this)" onfocus="focusing(this)">
                          {% for s in types %}
                              <option value="{{s.id}}">{{s.label}}</option>
                          {% endfor %}
                      </select>
                  </div>
                  <div class='form-group'>
                      <label for='region'>Region</label>
                      <select name='region' id='region' class='form-control'
                          onblur="blurring(this)" onfocus="focusing(this)">
                          {% for o in regions %}
                              <option value="{{o.id}}">{{o.id}}</option>
                          {% endfor %}
                      </select>
                  </div>
                  <div class='form-group'>
                      <label for='distribution'>Images</label>
                      <select name='distribution' id='distribution' class='form-control'
                          onblur="blurring(this)" onfocus="focusing(this)">
                          {% for d in stackscript.images %}
                              <option value="{{d.id.id}}">{{d.id.id}}</option>
                          {% endfor %}
                      </select>
                  </div>
              </div>
              <div class='row'>
                  <input type="submit" value="Deploy Linode" class='btn btn-primary btn-lg'/>
              </div>
          </form>
          <script>
              function focusing(ele){
                  ele.parentElement.style.borderColor = "#337ab7";
              }
              function blurring(ele){
                  ele.parentElement.style.borderColor = "#cccccc";
              }
          </script>
      {% endblock %}

      Here the template begins with two statements: {% extends 'base.html' %} and a {% block content %} statement. These two tags tell Jinja2 to extend the code within base.html, and to place everything within {% block content %} ... {% endblock %} in configure.html between the corresponding {% block content %} ... {% endblock %} tags in base.html.

      configure.html includes Jinja2 logic, with the inclusion of for statements like {% for o in regions %}. These statements are like for statements in other languages, and are used to iterate over an array or list. In this example, it is iterating over the regions that we passed to the template from the index route. configure.html also contains variables, which are denoted by double curly brackets: {{ s.id }}.

      Create another file called error.html. This will be the template that appears whenever there is an error in the Linode deployment. Copy in the following code:

      templates/error.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      {% extends 'base.html' %}
      {% block content %}
          <div class='row'>
              <h1 class="pop">Error</h1>
              <p>{{error}}</p>
          </div>
          <div class='row' style='margin-top: 20px'>
              <a href='/' class='btn btn-lg btn-default'>Try Again</a>
          </div>
      {% endblock %}

      This template works the same way that configure.html does, by extending base.html and providing its own content block.

      Lastly, create another file called success.html. This file follows the pattern set by configure.html and error.html, and will present the user with a confirmation message whenever a Linode is successfully created. This message includes the Linode’s label, group, IP address, and password:

      templates/success.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      
      {% extends 'base.html' %}
      {% block content %}
          <div class='row'>
              <h1>Success!</h1>
              <p>{{application_name}} has been deployed to <span class="pop">{{linode.label}}</span> in the {{linode.group}} group.</p>
          </div>
          <div class='row'>
              <div class='boxy'>
                  <p>You can access your Linode with the following command:</p>
                  <code>ssh root@{{linode.ipv4[0]}}</code>
                  <br />
                  <br />
                  <p>Your root password is:</p>
                  <code>{{password}}</code>
              </div>
          </div>
      {% endblock %}

      Run Your App

      You are now ready to run your app. Change back to your project’s main directory:

      cd ~/linode-oauth-project
      

      Run the app.py script:

      python3 app.py
      

      Open your browser to the following URL:

      http://localhost:5000/
      

      You should be greeted with your new app. Select a plan, a region, and an image to deploy a Linode using the Linode API Python library.

      Next Steps

      The app you’ve created shows off some of the aspects of the Linode API Python library. You can use LinodeLoginClient to authorize your OAuth app with the appropriate scopes, and can create Linodes through the use of LinodeClient.

      In extending this app, you might want to add multiple functionalities, like creating NodeBalancers from a list of available Linodes, or managing domains. To achieve this goal you’ll probably want to separate the login logic from the Linode creation logic. One way to do this would be store the OAuth token in the session, implementing a time-based expiration mechanism to expire your tokens instead.

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link

      Create a Terraform Module


      Updated by Linode Contributed by Linode

      Terraform modules allow you to better organize your configuration code and make the code reusable. You can host your Terraform modules on remote version control services, like GitHub, for others to use. The Terraform Module Registry hosts community modules that you can reuse for your own Terraform configurations, or you can publish your own modules for consumption by the Terraform community.

      In this guide you will create a Linode StackScripts module. This module will deploy a Linode instance from a StackScript you will create. This module will include nested modules that split up the required resources between the root module, a linode_instance module, and a stackscripts module.

      Before You Begin

      1. Install Terraform on your local computer using the steps found in the Install Terraform section of the Use Terraform to Provision Linode Environments guide. Your Terraform project directory should be named linode_stackscripts.

      2. Terraform requires an API access token. Follow the Getting Started with the Linode API guide to obtain a token.

      3. Complete the steps in the Configure Git section of the Getting Started with Git guide.

      4. Review Deploy a WordPress Site using Terraform and StackScripts to familiarize yourself with the Linode provider’s StackScript resource.

      Standard Module Structure

      Terraform’s standard module structure provides guidance on file and directory layouts for reusable modules. If you would like to make your module public to the Terraform community, the recommended layout allows Terraform to generate documentation and index modules for the Terraform Module Registry.

      • The primary module structure requirement is that a root module must exist. The root module is the directory that holds the Terraform configuration files that are applied to build your desired infrastructure. These files provide an entry point into any nested modules you might utilize.

      • Any module should include, at minimum, a main.tf, a variables.tf, and an outputs.tf file. This naming convention is recommended, but not enforced.

        • If using nested modules to split up your infrastructure’s required resources, the main.tf file holds all your module blocks and any needed resources not contained within your nested modules. A simple module’s main.tf file, without any nested modules, declares all resources within this file.

        • The variables.tf and outputs.tf files contain input variable and output variable declarations. All variables and outputs should include descriptions.

      • If using nested modules, they should be located in a root module’s subdirectory named modules/.

      • If your modules will be hosted on Terraform’s Module Registry, root modules and any nested modules should contain a README.MD file with a description that explains the module’s intended use.

      • You can provide examples in a root module’s subdirectory named examples.

      Create the Linode StackScripts Module

      The Linode Stackscripts module will included two nested modules that split up the required resources between the root module, a linodes module, and a stackscripts module. When you are done creating all required Terraform files your directory structure will look as follows:

        
      linode_stackscripts/
      ├── main.tf
      ├── outputs.tf
      ├── secrets.tfvars
      ├── terraform
      ├── terraform.tfvars
      ├── variables.tf
      └── modules/
          ├── linodes/
          │   ├── main.tf
          │   ├── variables.tf
          │   └── outputs.tf
          └── stackscripts/
              ├── main.tf
              ├── variables.tf
              └── outputs.tf
      
      

      Note

      Your linode_stackscripts directory will likely contain other files related to the Terraform installation you completed prior to beginning the steps in this guide.

      Create the Linodes Module

      In this section, you will create the linodes module which will be in charge of creating your Linode instance. This module contains a main.tf file and corresponding variables.tf and outputs.tf files.

      1. If your Terraform project directory is not named linode_stackscripts, rename it before beginning and move into that directory:

        mv terraform linode_stackscripts
        cd linode_stackscripts
        
      2. Create the modules and linodes subdirectories:

        mkdir -p modules/linodes
        
      3. Using your preferred text editor, create a main.tf file in modules/linodes/ with the following resources:

        linode_stackscripts/modules/linodes/main.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        
        locals {
            key ="${var.key}"
        }
        
        resource "linode_sshkey" "main_key" {
            label = "${var.key_label}"
            ssh_key = "${chomp(file(local.key))}"
        }
        
        resource "linode_instance" "linode_id" {
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            authorized_keys = [ "${linode_sshkey.main_key.ssh_key}" ]
            root_pass = "${var.root_pass}"
            stackscript_id = "${var.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        The main.tf file declares a linode_instance resource that deploys a Linode using a StackScript. Notice that all argument values use interpolation syntax to access variable values. You will declare the variables next and provide the variable values in the root module’s terraform.tfvars file. Using separate files for variable declaration and assignment parameterizes your configurations and allows them to be reused as modules.

        Let’s take a closer look at each block in the main.tf configuration file.

        1
        2
        3
        4
        5
        6
        7
        8
        
        locals {
            key ="${var.key}"
        }
        
        resource "linode_sshkey" "main_key" {
            label = "${var.key_label}"
            ssh_key = "${chomp(file(local.key))}"
        }
        • The locals stanza declares a local variable key whose value will be provided by an input variable.

        • The linode_sshkey resource will create Linode SSH Keys tied to your Linode account. These keys can be reused for future Linode deployments once the resource has been created. ssh_key = "${chomp(file(local.key))}" uses Terraform’s built-in function file() to provide a local file path to the public SSH key’s location. The location of the file path is the value of the local variable key. The chomp() built-in function removes trailing new lines from the SSH key.

          Note

          If you do not already have SSH keys, follow the steps in the Create an Authentication Key-pair section of the Securing Your Server Guide.
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        resource "linode_instance" "linode_id" {
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            authorized_keys = [ "${linode_sshkey.main_key.ssh_key}" ]
            root_pass = "${var.root_pass}"
            stackscript_id = "${var.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        The linode_instance resource creates a Linode instance with the listed arguments. Please note the following information:

        • The authorized_keys argument uses the SSH public key provided by the linode_sshkey resource in the previous stanza. This argument expects a value of type list, so the value must be wrapped in brackets.

        • To use an existing Linode StackScript you must use the stackscript_id argument and provide a valid ID as a value. Every StackScript is assigned a unique ID upon creation. Later on in the guide, you will create your own StackScript and expose its ID as an output variable in order to use its ID to deploy your Linode instance.

        • StackScripts support user defined data. This means a StackScript can use the UDF tag to create a variable whose value must be provided by the user of the script. This allows users to customize the behavior of a StackScript on a per-deployment basis. Any required UDF variable can be defined using the stackscript_data argument.

      4. Create the variables.tf file to define your resource’s required variables:

        linode_stackscripts/modules/linodes/variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        
        variable "key" {
          description = "Public SSH Key's path."
        }
        
        variable "key_label" {
          description = "new SSH key label"
        }
        
        variable "image" {
          description = "Image to use for Linode instance"
          default = "linode/ubuntu18.04"
        }
        
        variable "label" {
          description = "The Linode's label is for display purposes only, but must be unique."
          default = "default-linode"
        }
        
        variable "region" {
          description = "The region where your Linode will be located."
          default = "us-east"
        }
        
        variable "type" {
          description = "Your Linode's plan type."
          default = "g6-standard-1"
        }
        
        variable "authorized_keys" {
          description = "SSH Keys to use for the Linode."
          type = "list"
        }
        
        variable "root_pass" {
          description = "Your Linode's root user's password."
        }
        
        variable "stackscript_id" {
          description = "Stackscript ID."
        }
        
        variable "stackscript_data" {
          description = "Map of required StackScript UDF data."
          type = "map"
        }
        • Modules must include a description for each input variable to help document your configuration’s usage. This will make it easier for anyone else to use this module.

        • Every variable can contain a default value. The default value is only used if no other value is provided. For example, if you have a favorite Linux distribution, you may want to provide it as your image variable’s default value. In this case, linode/ubuntu18.04 is set as the default value.

        • You can declare a type for each variable. If no type is provided, the variable will default to type = "string".

        • Notice that the stackscript_data variable is of type = "map". This will allow you to provide values for as many UDF variables as your StackScript requires.

      5. Create the outputs.tf file:

        ~/linode_stackscripts/modules/linodes/outputs.tf
        1
        2
        3
        
        output "sshkey_linode" {
          value = "${linode_sshkey.main_key.ssh_key}"
        }

        The outputs.tf file exposes any values from the resources you declared in the main.tf file. Any exposed values can be used by any other module within the root module. The sshkey_linode output variable exposes the linode_sshkey resource’s public key.

      Now that the linodes module is complete, in the next section, you will create the stackscripts module.

      Create the StackScripts Module

      In this section you will create the StackScripts module. This module creates a linode_stackscripts resource which you can use to create and modify your own Linode StackScript.

      1. Ensure you are in the linode_stackscripts directory and create the stackscripts subdirectory:

        mkdir modules/stackscripts
        
      2. Using your preferred text editor, create a main.tf file in modules/stackscripts/ with the following resource:

        ~/linode_stackscripts/modules/stackscripts/main.tf
        1
        2
        3
        4
        5
        6
        7
        
        resource "linode_stackscript" "default" {
          label = "${var.stackscript_label}"
          description = "${var.description}"
          script = "${var.stackscript}"
          images = [ "${var.stackscript_image}" ]
          rev_note = "${var.rev_note}"
        }

        The main.tf file creates the linode_stackscript resource and provides the required configurations. All argument values use interpolation syntax to access input variable values. You will declare the input variables next and provide the variable values in the root module’s terraform.tfvars file. For more information on StackScripts see the Automate Deployments with StackScripts guide and the Linode APIv4 documentation.

      3. Create the variables.tf file to define your resource’s required variables:

        ~/linode_stackscripts/modules/stackscripts/variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        
        variable "stackscript_label" {
          description = "The StackScript's label is for display purposes only."
        }
        
        variable "description" {
          description = "A description for the StackScript."
        }
        
        variable "stackscript" {
          description = "The script to execute when provisioning a new Linode with this StackScript."
        }
        variable "stackscript_image" {
          description = " A list of Image IDs representing the Images that this StackScript is compatible for deploying with."
          type = "list"
        }
        variable "rev_note" {
          description = "This field allows you to add notes for the set of revisions made to this StackScript."
        }
      4. Create the outputs.tf file:

        ~/linode_stackscripts/modules/stackscripts/output.tf
        1
        2
        3
        
        output "stackscript_id" {
          value = "${linode_stackscript.default.id}"
        }

        The outputs.tf file exposes the value of the linode_stackscript resource’s ID. Every StackScript is assigned a unique ID upon creation. You will need this ID when creating your root module.

      You have now created the StackScripts module and are ready to use both modules within the root module. You will complete this work in the next section.

      Create the Root Module

      The root module will call the linode and stackscripts modules, satisfy their required variables and then apply those configurations to build your desired infrastructure. These configurations deploy a Linode based on a StackScript you will define in this section. When using nested modules, the modules will be hidden from your root configuration, so you’ll have to re-expose any variables and outputs you require.

      1. Ensure you are in the linode_stackscripts directory and create the main.tf file:

        linode_stackscripts/main.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        
        provider "linode" {
            token = "${var.token}"
        }
        
        module "stackscripts" {
            source = "./modules/stackscripts"
            stackscript_label = "${var.stackscript_label}"
            description = "${var.description}"
            stackscript = "${var.stackscript}"
            stackscript_image = [ "${var.stackscript_image}" ]
            rev_note = "${var.rev_note}"
        }
        
        module "linodes" {
            source = "./modules/linodes"
            key = "${var.key}"
            key_label = "${var.key_label}"
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            root_pass = "${var.root_pass}"
            authorized_keys = [ "${module.linodes.sshkey_linode}" ]
            stackscript_id = "${module.stackscripts.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        The main.tf file uses the linodes and stackscripts modules that were created in the previous sections and provides the required arguments. All argument values use interpolation syntax to access variable values, which you will declare in a variables.tf file and then provide corresponding values for in a terraform.tfvars file.

        Let’s review each block:

        1
        2
        3
        
        provider "linode" {
            token = "${var.token}"
        }

        The first stanza declares Linode as the provider that will manage the lifecycle of any resources declared throughout the configuration file. The Linode provider requires your Linode APIv4 token for authentication.

        1
        2
        3
        4
        5
        6
        7
        8
        
        module "stackscripts" {
            source = "./modules/stackscripts"
            stackscript_label = "${var.stackscript_label}"
            description = "${var.description}"
            stackscript = "${var.stackscript}"
            stackscript_image = [ "${var.stackscript_image}" ]
            rev_note = "${var.rev_note}"
        }

        The next stanza instructs Terraform to create an instance of the stackscripts module and instantiate any of the resources defined within the module. The source attribute provides the location of the child module’s source code and is required whenever you create an instance of a module. All other attributes are determined by the module. Notice that all the attributes included in the module block correspond to the linode_stackscript resource’s arguments declared in the main.tf file of the stackscripts module.

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        
        module "linodes" {
            source = "./modules/linodes"
            key = "${var.key}"
            key_label = "${var.key_label}"
            image = "${var.image}"
            label = "${var.label}"
            group = "${var.group}"
            region = "${var.region}"
            type = "${var.type}"
            root_pass = "${var.root_pass}"
            authorized_keys = [ "${module.linodes.sshkey_linode}" ]
            stackscript_id = "${module.stackscripts.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        This stanza creates an instance of the linodes module and then instantiates the resources you defined in the module. Notice that authorized_keys = [ "${module.linodes.sshkey_id}" ] and stackscript_id = "${module.stackscripts.stackscript_id}" both access values exposed as output variables by the linodes and stackscripts modules. Any module’s exposed output variables can be referenced in your root module’s main.tf file.

      2. Create the variables.tf file to declare the input variables required by the module instances:

        ~/linode_stackscripts/variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        
        variable "token" {
          description = " Linode API token"
        }
        
        variable "stackscript_label" {
          description = "The StackScript's label is for display purposes only."
        }
        
        variable "description" {
          description = "A description for the StackScript."
        }
        
        variable "stackscript" {
          description = "The script to execute when provisioning a new Linode with this StackScript."
        }
        
        variable "stackscript_image" {
          description = "A list of Image IDs representing the Images that this StackScript is compatible for deploying with."
        }
        
        variable "rev_note" {
          description = "This field allows you to add notes for the set of revisions made to this StackScript."
        }
        
        variable "key" {
          description = "Public SSH Key's path."
        }
        
        variable "key_label" {
          description = "New SSH key label."
        }
        
        variable "image" {
          description = "Image to use for Linode instance."
          default = "linode/ubuntu18.04"
        }
        
        variable "label" {
          description = "The Linode's label is for display purposes only, but must be unique."
          default = "default-linode"
        }
        
        variable "region" {
          description = "The region where your Linode will be located."
          default = "us-east"
        }
        
        variable "type" {
          description = "Your Linode's plan type."
          default = "g6-standard-1"
        }
        
        variable "root_pass" {
          description = "Your Linode's root user's password."
        }
        
        variable "stackscript_data" {
          description = "Map of required StackScript UDF data."
          type = "map"
        }
      3. Create the outputs.tf file:

        ~/linode_stackscripts/outputs.tf
        1
        2
        3
        
        output "stackscript_id" {
          value = "${module.stackscripts.stackscript_id}"
        }

        In the outputs.tf file you will re-expose the output variables exposed by the stackscripts module.

      4. Create the terraform.tfvars file to provide values for all input variables defined in the variables.tf file. This file will exclude any values that provide sensitive data, like passwords and API tokens. A file containing sensitive values will be created in the next step:

        ~/linode_stackscripts/terraform.tfvars
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        
        key = "~/.ssh/id_rsa.pub"
        key_label = "my-ssh-key"
        label = "my-linode"
        stackscript_data {
          my_username = "username"
          my_hostname = "linode-hostname"
        }
        stackscript_id = "base-ubuntu-deployment"
        stackscript_label = "base-ubuntu-deployment"
        description = "A base deployment for Ubuntu 18.04 that creates a limited user account."
        stackscript = <<EOF
        #!/bin/bash
        # <UDF name="my_hostname" Label="Linode's Hostname" />
        # <UDF name="my_username" Label="Limited user account" />
        # <UDF name="my_password" Label="Limited user account's password" />
        # <UDF name="my_userpubkey" Label="Limited user account's public key" />
        
        source <ssinclude StackScriptID="1">
        
        set -x
        
        MY_IP=system_primary_ip
        system_set_hostname "$MY_HOSTNAME"
        system_add_host_entry "$MY_IP" "$MY_HOSTNAME"
        user_add_sudo "$MY_USERNAME" "$MY_PASSWORD"
        user_add_pubkey "$MY_USERNAME" "$MY_USERPUBKEY"
        ssh_disable_root
        goodstuff
        EOF
        stackscript_image = "linode/ubuntu18.04"
        rev_note = "First revision of my StackScript created with the Linode Terraform provider."

        The terraform.tfvars file supplies all values required by the linodes and stackscripts modules. Ensure you replace any values with your own values when using this example file.

        The stackscript variable provides the actual contents of the StackScript you create. This example StackScript requires four UDF values: my_hostname, my_username, my_password, and my_userpubkey. The my_hostname and my_username values are supplied by the stackscript_data map. The my_password and my_userpubkey values will be provided in the next step.

        The StackScript will then use these values to create a limited user account; set a hostname; add a host entry; add the created user to the sudo group; disable SSH access for the root user; and install vim, wget, and less. This StackScript uses bash functions defined in the Linode Community StackScript Bash Library.

      5. Create a file named secrets.tfvars to hold any sensitive values:

        ~/linode_stackscripts/secrets.tfvars
        1
        2
        3
        4
        5
        6
        
        token = "my-linode-api-token"
        root_pass = "my-secure-root-password"
        stackscript_data {
          my_password = "my-limited-users-password"
          my_userpubkey = "my-public-ssh-key"
        }

        This file contains all sensitive data needed for your Linode deployment. Ensure you replace all values with your own secure passwords and your Linode account’s APIv4 token. This file should never be tracked in version control software and should be listed in your .gitignore file if using GitHub.

        Note

      You are now ready to apply your linode_stackscripts module’s Terraform configuration. These steps will be completed in the next section.

      Initialize, Plan and Apply the Terraform Configuration

      Whenever a new provider is used in a Terraform configuration, it must first be initialized. The initialization process downloads and installs the provider’s plugin and performs any other steps needed for its use. Before applying your configuration, it is also useful to view your configuration’s execution plan before making any actual changes to your infrastructure. In this section, you will complete all these steps.

      1. Initialize the Linode provider. Ensure you are in the linode_stackscripts directory before running this command:

        terraform init
        

        You will see a message that confirms that the provider plugins have been successfully initialized.

      2. Run the Terraform plan command:

        terraform plan -var-file="secrets.tfvars" -var-file="terraform.tfvars"
        

        Terraform plan won’t take any action or make any changes on your Linode account. Instead, an analysis is done to determine which actions (i.e. Linode instance creations, deletions, or modifications) are required to achieve the state described in your configuration.

      3. You are now ready to create the infrastructure defined in your root module’s main.tf configuration file:

        terraform apply -var-file="secrets.tfvars" -var-file="terraform.tfvars"
        

        Since you are using multiple variable value files, you must call each file individually using the var-file argument. You will be prompted to confirm the apply action. Type yes and hit enter. Terraform will begin to create the resources you’ve defined throughout this guide. This process will take a couple of minutes to complete. Once the infrastructure has been successfully built you will see a similar output:

          
          Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
            
        
      4. To verify the deployment, retrieve your Linode instance’s IP address:

        terraform show | grep 'ip_address'
        

        You should see a similar output:

          
                ip_address = 192.0.2.0
              
        
      5. Open a new shell session and SSH into your Linode using the IP address you retrieved in the previous step and the username you defined in the terraform.tfvars file’s my_username variable:

        ssh username@192.0.2.0
        

        You should be able to access your Linode and then verify that what you defined in the StackScript was executed.

      Version Control Your Terraform Module

      To make the linode_stackscripts module available to other team members, you can version control it using GitHub. Before completing the steps in this section, ensure you have completed the steps in the Configure Git section of the Getting Started with Git guide.

      1. In the linode_stackscripts directory create a .gitignore file:

        ~/linode_stackscripts/.gitignore
        1
        2
        3
        4
        
        secrets.tfvars
        .terraform/
        terraform/
        terraform.tfstate

        Note

        If there are any files related to the Terraform installation steps completed before beginning this guide (i.e zip files and checksum files), you can remove these files from the linode_stackscripts directory, since you should not track them in version control and they are no longer necessary.

      2. Initialize the git repository:

        git init
        

        Stage all the files you’ve created so far for your first commit:

        git add -A
        
      3. Commit all the linode_stackscripts files:

        git commit -m "Initial commit"
        
      4. Navigate to your GitHub account and create a new repository. Ensure you name the repository the same name as that of your Terraform module. In this example, the GitHub repository will be named linode_stackscripts.

      5. At the top of your GitHub repository’s Quick Setup page, copy the remote repository URL.

      6. Return to your local computer’s linode_stackscripts directory and add the URL for the remote repository:

        git remote add origin https://github.com/my-github/linode_stackscripts.git
        
      7. Push your local linode_stackscripts repository to your remote GitHub repository:

        git push -u origin master
        

      Your Terraform module is now tracked via GitHub and can be used, shared and modified by anyone who has access to your GitHub account.

      Invoking Your GitHub-Hosted Module

      In the future, you can source this module from GitHub within your Terraform module declarations. You would write your module block like the following:

      1
      2
      3
      4
      5
      6
      
      module "linode_stackscripts" {
          source = "github.com/username/linode_stackscripts"
      
          VARIABLES HERE
          . . .
      }

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link