Skip to main content

the avatar of Nathan Wolf

a silhouette of a person's head and shoulders, used as a default avatar

LattePanda Gigglescore

A Gigglescore is a ratio score of price to performance for single-board-computers like the LattePanda or Raspberry Pi. A lower Gigglescore means a better value for the money. A higher one is worse. You can see more here: https://gigglescore.com/

My LattePanda:

sudo ./benchmark.sh 149
Repository 'openSUSE-Leap-15.0-Non-Oss' is up to date.
Repository 'openSUSE-Leap-15.0-Oss' is up to date.
Repository 'openSUSE-Leap-15.0-Update' is up to date.
Repository 'openSUSE-Leap-15.0-Update-Non-Oss' is up to date.
All repositories have been refreshed.
Category5.TV SBC Benchmark v1.1
Powered by sysbench 1.0.11
Number of threads for this SBC: 4
Performing CPU Benchmark… WARNING: the --test option is deprecated. You can pass a script name or path on the command line without any options.
576.760 events per second. Price: Ģ930.02 per unit.
Performing RAM Benchmark… WARNING: the --test option is deprecated. You can pass a script name or path on the command line without any options.
3,625,781.466 events per second. Price: Ģ0.15 per unit.
Performing Mutex Benchmark… WARNING: the --test option is deprecated. You can pass a script name or path on the command line without any options.
6.873 events per second. Price: Ģ7.80 per unit.

Total Giggle cost of this board: Ģ1,397.58

Giggles (Ģ) are a cost comparison that takes cost and performance into account. While the figure itself is not a direct translation of a dollar value, it works the same way: A board with a lower Giggle value costs less for the performance.
If a board has a high Giggle value, it means for its performance, it is expensive. Giggles help you determine if a board is better bang-for-the-buck, even if it has a different real-world dollar value. Total Giggle cost does not include I/O since that can be impacted by which SD card you choose. Lower Ģ is better.

Being that the suggested retail price is currently $149, we get a Gigglescore of 1,397.58. This is right between the Raspberry Pi 3 B+ and the ODROID XU4 in terms of value for the dollar.

the avatar of Nathan Wolf

Sabayon Linux | Review from an openSUSE User

In my quest to further cement that openSUSE is the greatest Linux distribution ever, I have kicked the tires of yet another Linux Distribution, Sabayon. What Surprised me about this distribution was that it was Gentoo based yet installed very quickly, performed its updates quickly and was configured pretty decently out of the box. I … Continue reading Sabayon Linux | Review from an openSUSE User

the avatar of Michal Čihař

Weblate 3.6

Weblate 3.6 has been released today. It brings rewritten notifications, user data download and several other improvements. It also sets depreciation timeline for Python 2 installations - after April 2020 Weblate will only support Python 3.

Full list of changes:

  • Add support for downloading user data.
  • Addons are now automatically triggered upon installation.
  • Improved instructions for resolving merge conflicts.
  • Cleanup addon is now compatible with app store metadata translations.
  • Configurable language code syntax when adding new translations.
  • Warn about using Python 2 with planned termination of support in April 2020.
  • Extract special chars from the source string for visual keyboard.
  • Extended contributor stats to reflect both source and target counts.
  • Admins and consistency addons can now add translations even if disabled for users.
  • Fixed description of toggle disabling Language-Team header manipulation.
  • Notify users mentioned in comments.
  • Removed file format autodetection from component setup.
  • Fixed generating MO file for monolingual PO files.
  • Added digest notifications.
  • Added support for muting component notifications.
  • Added notifications for new alerts, whiteboard messages or components.
  • Notifications for administered projects can now be configured.
  • Improved handling of three letter language codes.

If you are upgrading from older version, please follow our upgrading instructions.

You can find more information about Weblate on https://weblate.org, the code is hosted on Github. If you are curious how it looks, you can try it out on demo server. Weblate is also being used on https://hosted.weblate.org/ as official translating service for phpMyAdmin, OsmAnd, Turris, FreedomBox, Weblate itself and many other projects.

Should you be looking for hosting of translations for your project, I'm happy to host them for you or help with setting it up on your infrastructure.

Further development of Weblate would not be possible without people providing donations, thanks to everybody who have helped so far! The roadmap for next release is just being prepared, you can influence this by expressing support for individual issues either by comments or by providing bounty for them.

Filed under: Debian English SUSE Weblate

the avatar of Nathan Wolf

the avatar of FreeAptitude

Upgrading openSUSE with zypper

With no doubt, an installation from scratch allows to get rid of all misconfigurations, packages installed once and never used, and broken or unneeded dependencies that most of the times we accumulate from time to time while playing new applications or system settings, upgrading openSUSE Leap through zypper instead, might perform enough well and, at the same time, avoiding to repeat the standard, several, boring configuration steps, to save time.

the avatar of Sébastien sogal Poher

Nouvelles de Tumbleweed en semaine 16/2019: mise à jour de Curl, Salt et de la suite FFmpeg

Trois clichés openSUSE Tumbleweed de qualité ont été publiés depuis jeudi dernier avec des paquets mis à jour pour Curl, Salt, FFmpeg et plus.

Mozilla Firefox a publié une version mineure de la version 66.0.3 dans le dernier instantané Tumbleweed 20190415. Le navigateur a résolu certains problèmes de performances avec certains jeux HTML5 et fourni un plug-in de recherche Baidu destiné aux utilisateurs chinois et à l’espace Internet chinois. Curl 7.64.1, l'outil de ligne de commande permettant de transférer des données à l'aide de divers protocoles, a corrigé de nombreux bogues et ajouté des bibliothèques supplémentaires pour vérifier la prise en charge du protocole LDAP (Lightweight Directory Access Protocol). La mise à jour de libvirt 5.2.0 a supprimé quelques correctifs et ajouté plusieurs nouvelles fonctionnalités, telles que les capacités de pool de stockage, pour obtenir une liste de sortie XML plus détaillée pour l'interface de programmation d'application (API) virConnectGetStoragePoolCapabilites. Libvirt a également activé la sélection automatique du microprogramme pour l'émulateur open source QEMU. Le tout nouveau paquet salt 2019.2.0 de Tumbleweed a amélioré l'automatisation du réseau et étendu la prise en charge de divers systèmes d'exploitation via le réseau, ainsi que de fonctionnalités de manipulation de la configuration ou d'exécution de commandes opérationnelles. Salt a également ajouté l'exécution de playbooks à la version 2019.2.0 avec la fonction playbookset inclut un module pour les states ansible, qui peut être utilisé sur un hôte ciblé pour exécuter des playbooks, ou utilisé dans un orchestrateur de states. Selon l'évaluateur de Tumbleweed, l’instantané avait une cote de 95 au moment de la publication de cet article.

Le cliché 20190412 a obtenu une note de 94 et a apporté une mise à jour à Ceph qui a ajouté une option distincte permettant de configurer un port SSL (Secure Sockets Layer). Le paquet cifs-utils 6.9, qui fait partie du projet Samba, a ajouté des correctifs pour Azure et supprimé plusieurs bogues. Le paquet libssh2_org 1.8.2 a rectifié un correctif mal appliqué qui cassait sa version précédente. Quelques paquets YaST comportaient des mises à jour, comme le paquet yast2-storage-ng 4.2.5, qui permet un nouveau format pour importer/exporter des lecteurs NFS (Network File System).

L’instantané 20190411 a démarré la semaine et affichait un score modérément stable de 89. Cet instantané apportait le noyau Linux 5.0.7 et offrait un potentiel d’atténuation pour un appel système ptrace pour PowerPC. Il y avait quelques corrections de bugs pour les codecs, les filtres et les formats dans la mise à jour 4.1.3 de ffmpeg. Le connecteur JavaScript pour GNOME, gjs 1.56.0, contenaient des modifications très importantes par rapport à la version précédente 1.54.3 de Tumbleweed. Les changelog précédents ont identifié un bogue GNU Compiler Collection 9 et ajouté des règles ESLint. La nouvelle version était une version stable. Le paquet python-kiwi 9.17.35 a corrigé les régressions pour le module kiwi-repart dracut. Le package wget 1.20.3 a corrigé la vulnérabilité de débordement de la mémoire tampon trouvée dans le Common Vulnerabilities and Exposures (CVE) 2019-5953. L’éditeur de texte vim 8.1.1137 a corrigé plusieurs bogues, dont un test Python qui n’effaçait pas le tampon caché et une espace dans la colonne de numérotation de ligne qui se trouvait du mauvais côté lorsque le paramètre rightleft était activé.

the avatar of Chun-Hung sakana Huang

ansible with openSUSE Leap 15 container image 建立小記

ansible with openSUSE Leap 15 container image 建立小記

OS: openSUSE Leap 15


最近換了 MacAir 13 Mojave 10.14.4


嘗試在 Mac Mojave 上面裝 ansible[azure], 但是經歷了太多版本相容性的問題
-- > 放棄, 決定使用 openSUSE Leap 15 container 來解決


以下是我的 Dockerfile


# openSUSE Leap 15 with ansible, azure-cli
FROM opensuse/leap:15


# Author
# MAINTAINER 已經棄用, 之後要使用 LABEL 方式
LABEL maintainer="sakana@cycu.org.tw"


# Install python2-pip, upgrade pip, ansible[azure]
RUN zypper install -y python2-pip && \
 pip2 install --upgrade pip && \
 pip2 install ansible[azure]


# Install wget, download azure_rm.py, set permission
RUN zypper install -y wget && \
 wget  https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/azure_rm.py && \
 chmod a+x azure_rm.py


# Install azure-cli
RUN zypper install -y curl && \
 rpm --import https://packages.microsoft.com/keys/microsoft.asc && \
 zypper addrepo --name 'Azure CLI' --check https://packages.microsoft.com/yumrepos/azure-cli azure-cli && \
 zypper install --from azure-cli -y azure-cli


#install vim
RUN zypper install -y vim

使用 docker build 指令將他打包成 image 並上傳到 docker hub

要使用的方式很簡單, 預設的 Tag 為 latest
下載 docker image
> docker  pull  sakana/ansible_opensuse15


這個 image 包含
  • ansible
  • azure-cli
  • azure SDK
  • azure_rm.py ( Dynamic inventory 使用 )
    • 但是最近 Azure 改變驗證的方式, 所以目前 azure_rm.py 可能有點問題, 還需要觀察還有實驗
      • 原本驗證檔案是看 ~/.azure/credentials
      • 現在可能會去看 ~/.azure/azureProfile.json


使用方式很簡單


> docker  run  -it  sakana/ansible_opensuse15  /bin/bash


在 container 內執行  az login 指令
# az  login


  • 會被要求開啟瀏覽器進行帳號驗證
  • 驗證成功會自動建立 ~/.azure 目錄以及相關驗證檔案


接下來就可以開始使用 ansible 指令進行管理
日後計畫把  ansible with aws 或是 ansible with gcp 放進來


~ enjoy it


Reference:

the avatar of Federico Mena-Quintero

Containing mutability in GObjects

Traditionally, GObject implementations in C are mutable: you instantiate a GObject and then change its state via method calls. Sometimes this is expected and desired; a GtkCheckButton widget certainly can change its internal state from pressed to not pressed, for example.

Other times, objects are mutable while they are being "assembled" or "configured", and only yield a final immutable result until later. This is the case for RsvgHandle from librsvg.

Please bear with me while I write about the history of the RsvgHandle API and why it ended up with different ways of doing the same thing.

The traditional RsvgHandle API

The final purpose of an RsvgHandle is to represent an SVG document loaded in memory. Once it is loaded, the SVG document does not change, as librsvg does not support animation or creating/removing SVG elements; it is a static renderer.

However, before an RsvgHandle achieves its immutable state, it has to be loaded first. Loading can be done in two ways:

  • The historical/deprecated way, using the rsvg_handle_write() and rsvg_handle_close() APIs. Plenty of code in GNOME used this write/close idiom before GLib got a good abstraction for streams; you can see another example in GdkPixbufLoader. The idea is that applications do this:
file = open a file...;
handle = rsvg_handle_new ();

while (file has more data) {
   rsvg_handle_write(handle, a bit of data);
}

rsvg_handle_close (handle);

// now the handle is fully loaded and immutable

rsvg_handle_render (handle, ...);
file = g_file_new_for_path ("/foo/bar.svg");
stream = g_file_read (file, ...);
handle = rsvg_handle_new ();

rsvg_handle_read_stream_sync (handle, stream, ...);

// now the handle is fully loaded and immutable

rsvg_handle_render (handle, ...);

A bit of history

Let's consider a few of RsvgHandle's functions.

Constructors:

  • rsvg_handle_new()
  • rsvg_handle_new_with_flags()

Configure the handle for loading:

  • rsvg_handle_set_base_uri()
  • rsvg_handle_set_base_gfile()

Deprecated loading API:

  • rsvg_handle_write()
  • rsvg_handle_close()

Streaming API:

  • rsvg_handle_read_stream_sync()

When librsvg first acquired the concept of an RsvgHandle, it just had rsvg_handle_new() with no arguments. About 9 years later, it got rsvg_handle_new_with_flags() to allow more options, but it took another 2 years to actually add some usable flags — the first one was to configure the parsing limits in the underlying calls to libxml2.

About 3 years after RsvgHandle appeared, it got rsvg_handle_set_base_uri() to configure the "base URI" against which relative references in the SVG document get resolved. For example, if you are reading /foo/bar.svg and it contains an element like <image xlink:ref="smiley.png"/>, then librsvg needs to be able to produce the path /foo/smiley.png and that is done relative to the base URI. (The base URI is implicit when reading from a specific SVG file, but it needs to be provided when reading from an arbitrary stream that may not even come from a file.)

Initially RsvgHandle had the write/close APIs, and 8 years later it got the streaming functions once GIO appeared. Eventually the streaming API would be the preferred one, instead of just being a convenience for those brave new apps that started using GIO.

A summary of librsvg's API may be something like:

  • librsvg gets written initially; it doesn't even have an RsvgHandle, and just provides a single function which takes a FILE * and renders it to a GdkPixbuf.

  • That gets replaced with RsvgHandle, its single rsvg_handle_new() constructor, and the write/close API to feed it data progressively.

  • GIO appears, we get the first widespread streaming APIs in GNOME, and RsvgHandle gets the ability to read from streams.

  • RsvgHandle gets rsvg_handle_new_with_flags() because now apps may want to configure extra stuff for libxml2.

  • When Cairo appears and librsvg is ported to it, RsvgHandle gets an extra flag so that SVGs rendered to PDF can embed image data efficiently.

It's a convoluted history, but git log -- rsvg.h makes it accessible.

Where is the mutability?

An RsvgHandle gets created, with flags or without. It's empty, and doesn't know if it will be given data with the write/close API or with the streaming API. Also, someone may call set_base_uri() on it. So, the handle must remain mutable while it is being populated with data. After that, it can say, "no more changes, I'm done".

In C, this doesn't even have a name. Everything is mutable by default all the time. This monster was the private data of RsvgHandle before it got ported to Rust:

struct RsvgHandlePrivate {
    // set during construction
    RsvgHandleFlags flags;

    // GObject-ism
    gboolean is_disposed;

    // Extra crap for a deprecated API
    RsvgSizeFunc size_func;
    gpointer user_data;
    GDestroyNotify user_data_destroy;

    // Data only used while parsing an SVG
    RsvgHandleState state;
    RsvgDefs *defs;
    guint nest_level;
    RsvgNode *currentnode;
    RsvgNode *treebase;
    GHashTable *css_props;
    RsvgSaxHandler *handler;
    int handler_nest;
    GHashTable *entities;
    xmlParserCtxtPtr ctxt;
    GError **error;
    GCancellable *cancellable;
    GInputStream *compressed_input_stream;

    // Data only used while rendering
    double dpi_x;
    double dpi_y;

    // The famous base URI, set before loading
    gchar *base_uri;
    GFile *base_gfile;

    // Some internal stuff
    gboolean in_loop;
    gboolean is_testing;
};

"Single responsibility principle"? This is a horror show. That RsvgHandlePrivate struct has all of these:

  • Data only settable during construction (flags)
  • Data set after construction, but which may only be set before loading (base URI)
  • Highly mutable data used only during the loading stage: state machines, XML parsers, a stack of XML elements, CSS properties...
  • The DPI (dots per inch) values only used during rendering.
  • Assorted fields used at various stages of the handle's life.

It took a lot of refactoring to get the code to a point where it was clear that an RsvgHandle in fact has distinct stages during its lifetime, and that some of that data should only live during a particular stage. Before, everything seemed a jumble of fields, used at various unclear points in the code (for the struct listing above, I've grouped related fields together — they were somewhat shuffled in the original code!).

What would a better separation look like?

In the master branch, now librsvg has this:

/// Contains all the interior mutability for a RsvgHandle to be called
/// from the C API.
pub struct CHandle {
    dpi: Cell<Dpi>,
    load_flags: Cell<LoadFlags>,

    base_url: RefCell<Option<Url>>,
    // needed because the C api returns *const char
    base_url_cstring: RefCell<Option<CString>>,

    size_callback: RefCell<SizeCallback>,
    is_testing: Cell<bool>,
    load_state: RefCell<LoadState>,
}

Internally, that CHandle struct is now the private data of the public RsvgHandle object. Note that all of CHandle's fields are a Cell<> or RefCell<>: in Rust terms, this means that those fields allow for "interior mutability" in the CHandle struct: they can be modified after intialization.

The last field's cell, load_state, contains this type:

enum LoadState {
    Start,

    // Being loaded using the legacy write()/close() API
    Loading { buffer: Vec<u8> },

    // Fully loaded, with a Handle to an SVG document
    ClosedOk { handle: Handle },

    ClosedError,
}

A CHandle starts in the Start state, where it doesn't know if it will be loaded with a stream, or with the legacy write/close API.

If the caller uses the write/close API, the handle moves to the Loading state, which has a buffer where it accumulates the data being fed to it.

But if the caller uses the stream API, the handle tries to parse an SVG document from the stream, and it moves either to the ClosedOk state, or to the ClosedError state if there is a parse error.

Correspondingly, when using the write/close API, when the caller finally calls rsvg_handle_close(), the handle creates a stream for the buffer, parses it, and also gets either into the ClosedOk or ClosedError state.

If you look at the variant ClosedOk { handle: Handle }, it contains a fully loaded Handle inside, which right now is just a wrapper around a reference-counted Svg object:

pub struct Handle {
    svg: Rc<Svg>,
}

The reason why LoadState::ClosedOk does not contain an Rc<Svg> directly, and instead wraps it with a Handle, is that this is just the first pass at refactoring. Also, Handle contains some API-level logic which I'm not completely sure makes sense as a lower-level Svg object. We'll see.

Couldn't you move more of CHandle's fields into LoadState?

Sort of, kind of, but the public API still lets one do things like call rsvg_handle_get_base_uri() after the handle is fully loaded, even though its result will be of little value. So, the fields that hold the base_uri information are kept in the longer-lived CHandle, not in the individual variants of LoadState.

How does this look from the Rust API?

CHandle implements the public C API of librsvg. Internally, Handle implements the basic "load from stream", "get the geometry of an SVG element", and "render to a Cairo context" functionality.

This basic functionality gets exported in a cleaner way through the Rust API, discussed previously. There is no interior mutability in there at all; that API uses a builder pattern to gradually configure an SVG loader, which returns a fully loaded SvgHandle, out of which you can create a CairoRenderer.

In fact, it may be possible to refactor all of this a bit and implement CHandle directly in terms of the new Rust API: in effect, use CHandle as the "holding space" while the SVG loader gets configured, and later turned into a fully loaded SvgHandle internally.

Conclusion

The C version of RsvgHandle's private structure used to have a bunch of fields. Without knowing the code, it was hard to know that they belonged in groups, and each group corresponded roughtly to a stage in the handle's lifetime.

It took plenty of refactoring to get the fields split up cleanly in librsvg's internals. The process of refactoring RsvgHandle's fields, and ensuring that the various states of a handle are consistent, in fact exposed a few bugs where the state was not being checked appropriately. The public C API remains the same as always, but has better internal checks now.

GObject APIs tend to allow for a lot of mutability via methods that change the internal state of objects. For RsvgHandle, it was possible to change this into a single CHandle that maintains the mutable data in a contained fashion, and later translates it internally into an immutable Handle that represents a fully-loaded SVG document. This scheme ties in well with the new Rust API for librsvg, which keeps everything immutable after creation.

the avatar of Chun-Hung sakana Huang

Ansible ec2_key module with openSUSE 小記

Ansible ec2_key module with openSUSE 小記

OS: openSUSE Leap 15
Ansible: 2.7.8

Requirements ( on host that executes module )
  • boto
  • boto3
  • Python >= 2.6

首先來查詢 boto 是否有安裝

# zypper  search  boto

Loading repository data...
Reading installed packages...

S | Name                          | Summary       | Type
--+-------------------------------+----------------------------------------+--------
i | google-roboto-fonts           | Mechanical yet friendly fonts       | package
 | google-roboto-mono-fonts      | Google Roboto Mono fonts         | package
 | python-gcs-oauth2-boto-plugin | GCE Storage plugin for OAuth2          | package
i | python2-boto                  | Amazon Web Services Library       | package
 | python2-boto3                 | Amazon Web Services Library         | package
 | python2-botocore              | Python interface for AWS         | package
 | python3-boto                  | Amazon Web Services Library         | package
 | python3-boto3                 | Amazon Web Services Library         | package


安裝 boto3
# pip  install  boto3

Requirement already satisfied: six>=1.5 in /usr/lib/python3.6/site-packages (from python-dateutil<3.0.0,>=2.1; python_version >= "2.7"->botocore<1.13.0,>=1.12.130->boto3) (1.11.0)
awscli 1.16.135 has requirement botocore==1.12.125, but you'll have botocore 1.12.130 which is incompatible.
Installing collected packages: botocore, boto3
 Found existing installation: botocore 1.12.125
   Uninstalling botocore-1.12.125:
     Successfully uninstalled botocore-1.12.125
Successfully installed boto3-1.9.130 botocore-1.12.130

有出現 awscli 1.16.135 要求 botocore 版本是 1.12.125 但是我們裝了 1.12.130
暫時先觀察一下

參考官方文件

連接的寫法像下列的方式
- hosts: localhost
 connection: local
 gather_facts: False

驗證的部份, 方式有兩種
  • 以 export 變數的方式
    • export AWS_ACCESS_KEY_ID='AK123'
    • export AWS_SECRET_ACCESS_KEY='abc123'
  • 存放在 playbook 中, 例如是 vars_file , 但是我覺得我會比較喜歡使用 vars_prompt , 但是缺點就是每個 ec2 moudle 都要寫 aws_access_key 與 aws_secret_key 這兩個參數
    • aws_access_key: "{{aws_access_key_id}}"
    • aws_secret_key: "{{aws_secret_access_key}}"




來建立一個測試用的 yaml 檔案
> vi   aws_create_ec2_key.yml

---
# AWS 相關測試
# edit by sakana 2019/4/14
# 官方建議的方式
- hosts: localhost
 connection: local
 gather_facts: False
#

 vars_prompt:
#要求使用者輸入 access key id 與 secret access key
   - name: "aws_access_key_id"
     prompt: "Enter aws_access_key_id"
     private: no

   - name: "aws_secret_access_key"
     prompt: "Enter aws_secret_access_key"
     private: no

   - name: "aws_region"
     prompt: "Enter AWS Region"
     private: no
     default: us-east-2

#詢問 key name
   - name: "ec2_key_name"
     prompt: "Enter ec2 key name"
     private: no


 tasks:
   - name: Create EC2 key pair
     ec2_key:
       aws_access_key: "{{ aws_access_key_id }}"
       aws_secret_key: "{{ aws_secret_access_key }}"
       name: "{{ ec2_key_name }}"
       region: "{{ aws_region }}"
       state: present
#使用 register 之後來將 key 匯出  
     register: ec2_key_result

# 使用copy module 來將傳回的資訊複製成檔案, 並設定權限
   - name: Save private key
     copy:
       content: "{{ ec2_key_result.key.private_key }}"
       dest: "~/{{ec2_key_name}}.pem"
       mode: 0400




參考網路上的作法, 使用 register 搭配 copy module 來儲存 key 並設定 permission

來進行實際測試

> ansible-playbook  aws_create_ec2_key.yml

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

Enter aws_access_key_id:  輸入YOUR_ACCESS_KEY_ID
Enter aws_secret_access_key: 輸入YOUR_SECRET_ACCESS_KEY
Enter AWS Region [us-east-2]:
Enter ec2 key name: test20190414

PLAY [localhost] **********************************************************************************************************************************

TASK [Create EC2 key pair] ************************************************************************************************************************
changed: [localhost]

TASK [Save private key] ***************************************************************************************************************************
changed: [localhost]

PLAY RECAP ****************************************************************************************************************************************
localhost                  : ok=2 changed=2 unreachable=0    failed=0  

觀察相關資訊
按照我們 playbook 內的設定, 存放到使用者家目錄
> ls  -l   ~/test20190414.pem
-r-------- 1 sakana users 1670  4月 14 11:42 /home/sakana/test20190414.pem

也可以到 Manage Console 觀察


接下來用同樣的方式測試移除 EC2 Key pair

> vi   aws_remove_ec2_key.yml

---
# AWS 相關測試
# edit by sakana 2019/4/14
# 官方建議的方式
- hosts: localhost
 connection: local
 gather_facts: False
#

 vars_prompt:
#要求使用者輸入 access key id 與 secret access key
   - name: "aws_access_key_id"
     prompt: "Enter aws_access_key_id"
     private: no

   - name: "aws_secret_access_key"
     prompt: "Enter aws_secret_access_key"
     private: no

   - name: "aws_region"
     prompt: "Enter AWS Region"
     private: no
     default: us-east-2

#詢問 key name
   - name: "ec2_key_name"
     prompt: "Enter ec2 key name"
     private: no


 tasks:
   - name: Create EC2 key pair
     ec2_key:
       aws_access_key: "{{ aws_access_key_id }}"
       aws_secret_key: "{{ aws_secret_access_key }}"
       name: "{{ ec2_key_name }}"
       region: "{{ aws_region }}"
       state: absent

主要就是 state 換成 absent

> ansible-playbook  aws_remove_ec2_key.yml

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

Enter aws_access_key_id: 輸入YOUR_ACCESS_KEY_ID
Enter aws_secret_access_key: 輸入YOUR_SECRET_ACCESS_KEY
Enter AWS Region [us-east-2]:
Enter ec2 key name: test20190414

PLAY [localhost] **********************************************************************************************************************************

TASK [Create EC2 key pair] ************************************************************************************************************************
changed: [localhost]

PLAY RECAP ****************************************************************************************************************************************
localhost                  : ok=1 changed=1 unreachable=0    failed=0   

可以到 Manage Console 觀察 Key Pair 有沒有被刪除
也記得去刪除家目錄下面的 Key

踏出 Ansible with AWS 一小步
~ enjoy it


Reference: